Class: Collavre::GoogleCalendarService

Inherits:
Object
  • Object
show all
Defined in:
app/services/collavre/google_calendar_service.rb

Instance Method Summary collapse

Constructor Details

#initialize(user:) ⇒ GoogleCalendarService

Returns a new instance of GoogleCalendarService.



8
9
10
11
12
13
# File 'app/services/collavre/google_calendar_service.rb', line 8

def initialize(user:)
  @user = user
  @service = Google::Apis::CalendarV3::CalendarService.new
  @service.client_options.application_name = "Collavre"
  @service.authorization = user_credentials
end

Instance Method Details

#create_google_event(calendar_id: "primary", start_time:, end_time:, summary:, description: nil, timezone: nil, location: nil, recurrence: nil, attendees: nil, reminders: nil, all_day: false) ⇒ Object

Creates a Google Calendar event. Optional params supported: location, recurrence (array), attendees (array of emails or attendee hashes), reminders (hash: { use_default: true/false, overrides: [{ method: ‘email’|‘popup’, minutes: Integer }, …] })



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'app/services/collavre/google_calendar_service.rb', line 18

def create_google_event(
  calendar_id: "primary",
  start_time:,
  end_time:,
  summary:,
  description: nil,
  timezone: nil,
  location: nil,
  recurrence: nil,
  attendees: nil,
  reminders: nil,
  all_day: false
)
  timezone ||= @user.timezone || Time.zone.tzinfo.name
  event_args = { summary: summary, description: description }

  if all_day
    # All-day events must use date (no time or timezone). End date is exclusive per Google Calendar API.
    start_date = start_time.to_date
    end_date_exclusive = end_time.to_date + 1
    event_args[:start] = { date: start_date.iso8601 }
    event_args[:end]   = { date: end_date_exclusive.iso8601 }
  else
    event_args[:start] = { date_time: start_time.iso8601, time_zone: timezone }
    event_args[:end]   = { date_time: end_time.iso8601,   time_zone: timezone }
  end

  event_args[:location] = location if location.present?
  event_args[:recurrence] = recurrence if recurrence.present?

  if attendees.present?
    event_args[:attendees] = Array(attendees).map do |a|
      if a.is_a?(String)
        Google::Apis::CalendarV3::EventAttendee.new(email: a)
      elsif a.is_a?(Hash)
        # Support keys like :email, :response_status, etc.
        Google::Apis::CalendarV3::EventAttendee.new(**a.symbolize_keys)
      else
        nil
      end
    end.compact
  end

  if reminders.present?
    use_default = reminders[:use_default]
    overrides = Array(reminders[:overrides]).map do |r|
      # IMPORTANT: Ruby client uses method_prop instead of method
      meth = r[:method] || r[:method_prop]
      mins = r[:minutes]
      Google::Apis::CalendarV3::EventReminder.new(method_prop: meth, minutes: mins)
    end
    event_args[:reminders] = Google::Apis::CalendarV3::Event::Reminders.new(use_default: !!use_default, overrides: overrides)
  end

  event = Google::Apis::CalendarV3::Event.new(**event_args)

  if @service.authorization.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_APP_CREATED)
    @user.calendar_id ||= create_app_calendar
    calendar_id = @user.calendar_id
  end
  @service.insert_event(calendar_id, event)
rescue Google::Apis::ClientError => e
  # Surface helpful error info to aid debugging 400 errors
  Rails.logger.error("Google Calendar insert_event 4xx: #{e.class} #{e.status_code} - #{e.message} body=#{e.body}")
  raise
end

#delete_event(event_id, calendar_id: "primary") ⇒ Object

Deletes a Google Calendar event.



86
87
88
89
90
91
92
93
94
# File 'app/services/collavre/google_calendar_service.rb', line 86

def delete_event(event_id, calendar_id: "primary")
  if @service.authorization.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_APP_CREATED)
    @user.calendar_id ||= create_app_calendar
    calendar_id = @user.calendar_id
  end
  @service.delete_event(calendar_id, event_id)
rescue Google::Apis::ClientError => e
  raise unless e.status_code == 404
end

#ensure_app_calendar!Object

Ensure user’s app calendar exists if the token has calendar.app.created scope. Returns the calendar_id if created/found, otherwise nil.



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'app/services/collavre/google_calendar_service.rb', line 171

def ensure_app_calendar!
  if @service.authorization.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_APP_CREATED)
    if @user.calendar_id.nil?
      @user.calendar_id = create_app_calendar
    else
      begin
        calendar = @service.get_calendar(@user.calendar_id)
        if calendar.id != @user.calendar_id
          @user.calendar_id = create_app_calendar
        end
      rescue Google::Apis::ClientError => e
        if e.status_code == 404
          Rails.logger.error("Google Calendar not found (deleted?) for user #{@user.id}, calendar_id=#{@user.calendar_id}")
          @user.calendar_id = create_app_calendar
        else
          Rails.logger.error("Google Calendar get_calendar error for user #{@user.id}: #{e.class} #{e.status_code} - #{e.message}")
          raise
        end
      rescue Google::Apis::AuthorizationError => e
        Rails.logger.error("Google Calendar get_calendar auth error for user #{@user.id}: #{e.message}")
        raise GoogleCalendarError, I18n.t("collavre.google_calendar.errors.reconnect")
      end
    end
  end
  @user.calendar_id
end

#list_calendarsObject



96
97
98
99
100
101
102
103
104
# File 'app/services/collavre/google_calendar_service.rb', line 96

def list_calendars
  @service.list_calendar_lists.items.map { |c| [ c.summary, c.id ] }.to_h
rescue Google::Apis::AuthorizationError => e
  Rails.logger.error("Google Calendar list_calendars auth error for user #{@user.id}: #{e.message}")
  raise GoogleCalendarError, I18n.t("collavre.google_calendar.errors.reconnect")
rescue Faraday::ConnectionFailed, Faraday::TimeoutError, Google::Apis::TransmissionError => e
  Rails.logger.error("Google Calendar list_calendars network error for user #{@user.id}: #{e.class} - #{e.message}")
  raise GoogleCalendarError, I18n.t("collavre.google_calendar.errors.network")
end