calendar-assistant 0.9.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/README.md +44 -22
  4. data/Rakefile +37 -6
  5. data/bin/calendar-assistant +3 -1
  6. data/lib/calendar_assistant.rb +14 -16
  7. data/lib/calendar_assistant/available_block.rb +1 -1
  8. data/lib/calendar_assistant/calendar_assistant.rb +21 -25
  9. data/lib/calendar_assistant/cli.rb +10 -10
  10. data/lib/calendar_assistant/cli/authorizer.rb +14 -14
  11. data/lib/calendar_assistant/cli/command_service.rb +2 -2
  12. data/lib/calendar_assistant/cli/commands.rb +47 -40
  13. data/lib/calendar_assistant/cli/config.rb +16 -17
  14. data/lib/calendar_assistant/cli/event_presenter.rb +2 -2
  15. data/lib/calendar_assistant/cli/event_set_presenter.rb +3 -3
  16. data/lib/calendar_assistant/cli/helpers.rb +7 -8
  17. data/lib/calendar_assistant/cli/linter_event_presenter.rb +3 -3
  18. data/lib/calendar_assistant/cli/linter_event_set_presenter.rb +4 -4
  19. data/lib/calendar_assistant/cli/printer.rb +15 -15
  20. data/lib/calendar_assistant/config.rb +11 -11
  21. data/lib/calendar_assistant/config/token_store.rb +4 -4
  22. data/lib/calendar_assistant/date_helpers.rb +1 -2
  23. data/lib/calendar_assistant/event.rb +54 -50
  24. data/lib/calendar_assistant/event_repository.rb +14 -15
  25. data/lib/calendar_assistant/event_repository_factory.rb +1 -1
  26. data/lib/calendar_assistant/event_set.rb +14 -14
  27. data/lib/calendar_assistant/extensions/google_apis_extensions.rb +1 -1
  28. data/lib/calendar_assistant/extensions/launchy_extensions.rb +7 -4
  29. data/lib/calendar_assistant/has_duration.rb +4 -5
  30. data/lib/calendar_assistant/lint_event_repository.rb +3 -3
  31. data/lib/calendar_assistant/location_config_validator.rb +3 -3
  32. data/lib/calendar_assistant/location_event_repository.rb +7 -8
  33. data/lib/calendar_assistant/predicate_collection.rb +1 -2
  34. data/lib/calendar_assistant/scheduler.rb +4 -5
  35. data/lib/calendar_assistant/string_helpers.rb +1 -1
  36. data/lib/calendar_assistant/version.rb +1 -1
  37. metadata +38 -30
@@ -3,9 +3,10 @@ class CalendarAssistant
3
3
  class Config
4
4
  autoload :TokenStore, "calendar_assistant/config/token_store"
5
5
 
6
- class NoTokensAuthorized < CalendarAssistant::BaseException;
6
+ class NoTokensAuthorized < CalendarAssistant::BaseException
7
7
  end
8
- class AccessingHashAsScalar < CalendarAssistant::BaseException;
8
+
9
+ class AccessingHashAsScalar < CalendarAssistant::BaseException
9
10
  end
10
11
 
11
12
  module Keys
@@ -57,16 +58,15 @@ class CalendarAssistant
57
58
 
58
59
  attr_reader :user_config, :options, :defaults
59
60
 
60
- def initialize options: {},
61
+ def initialize(options: {},
61
62
  user_config: {},
62
- defaults: DEFAULT_SETTINGS
63
-
63
+ defaults: DEFAULT_SETTINGS)
64
64
  @defaults = defaults
65
65
  @options = options
66
66
  @user_config = user_config
67
67
  end
68
68
 
69
- def in_env &block
69
+ def in_env(&block)
70
70
  # this is totally not thread-safe
71
71
  orig_b_o_d = BusinessTime::Config.beginning_of_workday
72
72
  orig_e_o_d = BusinessTime::Config.end_of_workday
@@ -98,7 +98,7 @@ class CalendarAssistant
98
98
  end
99
99
  end
100
100
 
101
- def get keypath
101
+ def get(keypath)
102
102
  rval = Config.find_in_hash(user_config, keypath)
103
103
 
104
104
  if rval.is_a?(Hash)
@@ -108,7 +108,7 @@ class CalendarAssistant
108
108
  rval
109
109
  end
110
110
 
111
- def set keypath, value
111
+ def set(keypath, value)
112
112
  Config.set_in_hash user_config, keypath, value
113
113
  end
114
114
 
@@ -116,7 +116,7 @@ class CalendarAssistant
116
116
  # note that, despite the name, this method returns both options
117
117
  # and settings
118
118
  #
119
- def setting setting_name
119
+ def setting(setting_name)
120
120
  context = Config.find_in_hash(options, Keys::Options::CONTEXT)
121
121
  Config.find_in_hash(options, setting_name) ||
122
122
  Config.find_in_hash(user_config, [Keys::SETTINGS, context, setting_name]) ||
@@ -190,14 +190,14 @@ class CalendarAssistant
190
190
  a
191
191
  end
192
192
 
193
- def self.find_in_hash hash, keypath
193
+ def self.find_in_hash(hash, keypath)
194
194
  split_keypath(keypath).inject(hash) do |current_val, key|
195
195
  break unless current_val.has_key?(key)
196
196
  current_val[key]
197
197
  end
198
198
  end
199
199
 
200
- def self.set_in_hash hash, keypath, new_value
200
+ def self.set_in_hash(hash, keypath, new_value)
201
201
  *path_parts, key = *split_keypath(keypath)
202
202
 
203
203
  current_hash = path_parts.inject(hash) do |current_val, path|
@@ -3,20 +3,20 @@ class CalendarAssistant
3
3
  class TokenStore
4
4
  attr_reader :config
5
5
 
6
- def initialize config
6
+ def initialize(config)
7
7
  @config = config
8
8
  end
9
9
 
10
- def delete id
10
+ def delete(id)
11
11
  config.tokens.delete(id)
12
12
  config.persist!
13
13
  end
14
14
 
15
- def load id
15
+ def load(id)
16
16
  config.tokens[id]
17
17
  end
18
18
 
19
- def store id, token
19
+ def store(id, token)
20
20
  config.tokens[id] = token
21
21
  config.persist!
22
22
  end
@@ -1,6 +1,6 @@
1
1
  class CalendarAssistant
2
2
  module DateHelpers
3
- def self.cast_dates attributes
3
+ def self.cast_dates(attributes)
4
4
  attributes.each_with_object({}) do |(key, value), object|
5
5
  if value.is_a?(Time) || value.is_a?(DateTime)
6
6
  object[key] = Google::Apis::CalendarV3::EventDateTime.new(date_time: value)
@@ -13,4 +13,3 @@ class CalendarAssistant
13
13
  end
14
14
  end
15
15
  end
16
-
@@ -29,49 +29,49 @@ class CalendarAssistant
29
29
  end
30
30
 
31
31
  PREDICATES = {
32
- "response": %I[
33
- accepted?
34
- declined?
35
- awaiting?
36
- tentative?
37
- ],
38
- "temporal": %I[
39
- all_day?
40
- past?
41
- current?
42
- future?
43
- ],
44
- "visibility": %I[
45
- private?
46
- public?
47
- explicitly_visible?
48
- visible_guestlist?
49
- ],
50
- "attributes": %I[
51
- location_event?
52
- self?
53
- one_on_one?
54
- busy?
55
- commitment?
56
- recurring?
57
- abandoned?
58
- anyone_can_add_self?
59
- attendees_omitted?
60
- end_time_unspecified?
61
- guests_can_invite_others?
62
- guests_can_modify?
63
- guests_can_see_other_guests?
64
- private_copy?
65
- locked?
66
- needs_action?
67
- ]
32
+ "response": %I[
33
+ accepted?
34
+ declined?
35
+ awaiting?
36
+ tentative?
37
+ ],
38
+ "temporal": %I[
39
+ all_day?
40
+ past?
41
+ current?
42
+ future?
43
+ ],
44
+ "visibility": %I[
45
+ private?
46
+ public?
47
+ explicitly_visible?
48
+ visible_guestlist?
49
+ ],
50
+ "attributes": %I[
51
+ location_event?
52
+ self?
53
+ one_on_one?
54
+ busy?
55
+ commitment?
56
+ recurring?
57
+ abandoned?
58
+ anyone_can_add_self?
59
+ attendees_omitted?
60
+ end_time_unspecified?
61
+ guests_can_invite_others?
62
+ guests_can_modify?
63
+ guests_can_see_other_guests?
64
+ private_copy?
65
+ locked?
66
+ needs_action?
67
+ ],
68
68
  }
69
69
 
70
70
  #
71
71
  # class methods
72
72
  #
73
73
 
74
- def self.location_event_prefix config
74
+ def self.location_event_prefix(config)
75
75
  icon = config[CalendarAssistant::Config::Keys::Settings::LOCATION_ICON]
76
76
  if nickname = config[CalendarAssistant::Config::Keys::Settings::NICKNAME]
77
77
  return "#{icon} #{nickname} @ "
@@ -87,13 +87,13 @@ class CalendarAssistant
87
87
  @config = config
88
88
  end
89
89
 
90
- def update **args
90
+ def update(**args)
91
91
  update!(**args)
92
92
  self
93
93
  end
94
94
 
95
95
  def location_event?
96
- !! summary.try(:starts_with?, Event.location_event_prefix(@config))
96
+ !!summary.try(:starts_with?, Event.location_event_prefix(@config))
97
97
  end
98
98
 
99
99
  def accepted?
@@ -167,15 +167,15 @@ class CalendarAssistant
167
167
 
168
168
  def other_human_attendees
169
169
  return nil if attendees.nil?
170
- attendees.select { |a| ! a.resource && ! a.self }
170
+ attendees.select { |a| !a.resource && !a.self }
171
171
  end
172
172
 
173
173
  def human_attendees
174
174
  return nil if attendees.nil?
175
- attendees.select { |a| ! a.resource }
175
+ attendees.select { |a| !a.resource }
176
176
  end
177
177
 
178
- def attendee id
178
+ def attendee(id)
179
179
  return nil if attendees.nil?
180
180
  attendees.find do |attendee|
181
181
  attendee.email == id
@@ -192,15 +192,19 @@ class CalendarAssistant
192
192
 
193
193
  def av_uri
194
194
  @av_uri ||= begin
195
- description_link = CalendarAssistant::StringHelpers.find_uri_for_domain(description, "zoom.us")
196
- return description_link if description_link
195
+ if conference_data && conference_data.conference_solution.name == "Zoom Meeting"
196
+ return conference_data.entry_points.detect{|d| d.entry_point_type == "video" }.uri
197
+ end
197
198
 
198
- location_link = CalendarAssistant::StringHelpers.find_uri_for_domain(location, "zoom.us")
199
- return location_link if location_link
199
+ description_link = CalendarAssistant::StringHelpers.find_uri_for_domain(description, "zoom.us")
200
+ return description_link if description_link
200
201
 
201
- return hangout_link if hangout_link
202
- nil
203
- end
202
+ location_link = CalendarAssistant::StringHelpers.find_uri_for_domain(location, "zoom.us")
203
+ return location_link if location_link
204
+
205
+ return hangout_link if hangout_link
206
+ nil
207
+ end
204
208
  end
205
209
  end
206
- end
210
+ end
@@ -1,6 +1,6 @@
1
1
  class CalendarAssistant
2
2
  class EventRepository
3
- class CalendarNotFoundException < CalendarAssistant::BaseException;
3
+ class CalendarNotFoundException < CalendarAssistant::BaseException
4
4
  end
5
5
 
6
6
  attr_reader :calendar, :calendar_id, :config
@@ -15,45 +15,44 @@ class CalendarAssistant
15
15
  raise
16
16
  end
17
17
 
18
- def in_tz &block
18
+ def in_tz(&block)
19
19
  CalendarAssistant.in_tz calendar.time_zone do
20
20
  yield
21
21
  end
22
22
  end
23
23
 
24
- def find time_range, predicates: {}
24
+ def find(time_range, predicates: {})
25
25
  events = @service.list_events(@calendar_id,
26
- time_min: time_range.first.iso8601,
27
- time_max: time_range.last.iso8601,
28
- order_by: "startTime",
29
- single_events: true,
30
- max_results: 2000,
31
- )
26
+ time_min: time_range.first.iso8601,
27
+ time_max: time_range.last.iso8601,
28
+ order_by: "startTime",
29
+ single_events: true,
30
+ max_results: 2000)
32
31
  events = events.items.map { |e| CalendarAssistant::Event.new(e, config: config) }
33
32
 
34
33
  events = filter_by_predicates(events, predicates) unless predicates.empty?
35
34
  CalendarAssistant::EventSet.new self, events
36
35
  end
37
36
 
38
- def new event_attributes
39
- event = Google::Apis::CalendarV3::Event.new DateHelpers.cast_dates(event_attributes)
37
+ def new(event_attributes)
38
+ event = Google::Apis::CalendarV3::Event.new(**DateHelpers.cast_dates(event_attributes))
40
39
  event.visibility ||= config.event_visibility
41
40
  CalendarAssistant::Event.new(event, config: config)
42
41
  end
43
42
 
44
- def create event_attributes
43
+ def create(event_attributes)
45
44
  new(event_attributes).tap do |event|
46
45
  @service.insert_event @calendar_id, event.__getobj__
47
46
  end
48
47
  end
49
48
 
50
- def delete event
51
- @service.delete_event @calendar_id, event.id
49
+ def delete(event)
50
+ @service.delete_event @calendar_id, event.id
52
51
  event
53
52
  end
54
53
 
55
54
  def update(event, attributes)
56
- event.update! DateHelpers.cast_dates(attributes)
55
+ event.update!(**DateHelpers.cast_dates(attributes))
57
56
  updated_event = @service.update_event @calendar_id, event.id, event
58
57
  CalendarAssistant::Event.new(updated_event, config: config)
59
58
  end
@@ -1,6 +1,6 @@
1
1
  class CalendarAssistant
2
2
  class EventRepositoryFactory
3
- def self.new_event_repository service, calendar_id, config: CalendarAssistant::Config.new, type: :base
3
+ def self.new_event_repository(service, calendar_id, config: CalendarAssistant::Config.new, type: :base)
4
4
  klass = case type
5
5
  when :location
6
6
  LocationEventRepository
@@ -7,7 +7,7 @@ class CalendarAssistant
7
7
  # - it could be a bare Event
8
8
  #
9
9
  class EventSet
10
- def self.new event_repository, events=nil
10
+ def self.new(event_repository, events = nil)
11
11
  if events.is_a?(EventSet::Hash)
12
12
  return EventSet::Hash.new event_repository, events.try(:events)
13
13
  end
@@ -23,17 +23,17 @@ class CalendarAssistant
23
23
  class Base
24
24
  attr_reader :event_repository, :events
25
25
 
26
- def initialize event_repository, events
26
+ def initialize(event_repository, events)
27
27
  @event_repository = event_repository
28
28
  @events = events
29
29
  end
30
30
 
31
- def == rhs
31
+ def ==(rhs)
32
32
  return false unless rhs.is_a?(self.class)
33
33
  self.event_repository == rhs.event_repository && self.events == rhs.events
34
34
  end
35
35
 
36
- def new new_events
36
+ def new(new_events)
37
37
  EventSet.new self.event_repository, new_events
38
38
  end
39
39
 
@@ -45,28 +45,28 @@ class CalendarAssistant
45
45
  end
46
46
 
47
47
  class Hash < EventSet::Base
48
- def ensure_keys keys, only: false
48
+ def ensure_keys(keys, only: false)
49
49
  keys.each do |key|
50
50
  events[key] = [] unless events.has_key?(key)
51
51
  end
52
52
  if only
53
53
  events.keys.each do |key|
54
- if ! keys.include? key
54
+ if !keys.include? key
55
55
  events.delete(key)
56
56
  end
57
57
  end
58
58
  end
59
59
  end
60
60
 
61
- def [] key
61
+ def [](key)
62
62
  events[key] ||= []
63
63
  end
64
64
 
65
- def []= key, value
65
+ def []=(key, value)
66
66
  events[key] = value
67
67
  end
68
68
 
69
- def available_blocks length: 1
69
+ def available_blocks(length: 1)
70
70
  event_repository.in_tz do
71
71
  dates = events.keys.sort
72
72
 
@@ -91,7 +91,7 @@ class CalendarAssistant
91
91
  avail_time[date] << AvailableBlock.new(start: start_time, end: e.start_time)
92
92
  end
93
93
  start_time = [e.end_time, start_time].max
94
- break if ! start_time.during_business_hours?
94
+ break if !start_time.during_business_hours?
95
95
  end
96
96
 
97
97
  if HasDuration.duration_in_seconds(start_time, end_time) >= length
@@ -105,18 +105,18 @@ class CalendarAssistant
105
105
  end
106
106
  end
107
107
 
108
- def intersection other, length: 1
108
+ def intersection(other, length: 1)
109
109
  set = new({})
110
110
  set.ensure_keys(events.keys + other.events.keys)
111
111
  set.events.keys.each do |date|
112
112
  events[date].each do |event_a|
113
113
  other.events[date].each do |event_b|
114
114
  if event_a.contains?(event_b.start_time) ||
115
- event_a.contains?(event_b.end_time-1) ||
115
+ event_a.contains?(event_b.end_time - 1) ||
116
116
  event_b.contains?(event_a.start_time) ||
117
- event_b.contains?(event_a.end_time-1)
117
+ event_b.contains?(event_a.end_time - 1)
118
118
  start_time = [event_a.start_time, event_b.start_time].max
119
- end_time = [event_a.end_time, event_b.end_time ].min
119
+ end_time = [event_a.end_time, event_b.end_time].min
120
120
  if HasDuration.duration_in_seconds(start_time, end_time) >= length
121
121
  set.events[date] << AvailableBlock.new(start: start_time, end: end_time)
122
122
  end
@@ -21,7 +21,7 @@ class Google::Apis::CalendarV3::EventDateTime
21
21
  date_time.strftime "%Y-%m-%d %H:%M"
22
22
  end
23
23
 
24
- def == rhs
24
+ def ==(rhs)
25
25
  if date
26
26
  return to_date == rhs.to_date
27
27
  end
@@ -12,9 +12,9 @@ require "launchy"
12
12
  #
13
13
  class CalendarAssistant
14
14
  class ZoomLaunchy < Launchy::Application::Browser
15
- ZOOM_URI_REGEXP = %r(https?://\w+.zoom.us/j/(\d+))
15
+ ZOOM_URI_REGEXP = %r(https?://\w+.zoom.us/j/(\d+)(\?(.*))?)
16
16
 
17
- def self.handles? uri
17
+ def self.handles?(uri)
18
18
  return true if ZOOM_URI_REGEXP.match(uri)
19
19
  end
20
20
 
@@ -26,13 +26,16 @@ class CalendarAssistant
26
26
  [find_executable("xdg-open")]
27
27
  end
28
28
 
29
- def open uri, options={}
29
+ def open(uri, options = {})
30
30
  command = host_os_family.app_list(self).compact.first
31
31
  if command.nil?
32
32
  super uri, options
33
33
  else
34
- confno = ZOOM_URI_REGEXP.match(uri)[1]
34
+ matches = ZOOM_URI_REGEXP.match(uri)
35
+ confno = matches[1]
36
+ params = matches[3]
35
37
  url = "zoommtg://zoom.us/join?confno=#{confno}"
38
+ url += "&#{params}" if params
36
39
  run command, [url]
37
40
  end
38
41
  end