Module: Cal4near

Defined in:
lib/cal4near.rb,
lib/cal4near/version.rb

Defined Under Namespace

Classes: Error

Constant Summary collapse

OOB_URI =
"urn:ietf:wg:oauth:2.0:oob".freeze
APPLICATION_NAME =
"Google Calendar API Ruby Quickstart".freeze
CREDENTIALS_PATH =
"credentials.json".freeze
TOKEN_PATH =

The file token.yaml stores the user’s access and refresh tokens, and is created automatically when the authorization flow completes for the first time.

"token.yaml".freeze
SCOPE =
Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY
START_DATE =

空き時間を検索する日時の範囲

DateTime.now.next_day(1)
END_DATE =
DateTime.now.next_day(30)
START_HOUR =

空き時間を検索する時間の範囲

9
END_HOUR =
19
DATE_FORMAT =
"%Y-%m-%d"
DATE_TIME_FORMAT =
"%Y-%m-%d %H:%M"
VERSION =
"0.2.0"

Class Method Summary collapse

Class Method Details

.authorizeGoogle::Auth::UserRefreshCredentials

Ensure valid credentials, either by restoring from the saved credentials files or intitiating an OAuth2 authorization. If authorization is required, the user’s default browser will be launched to approve the request.

Returns:

  • (Google::Auth::UserRefreshCredentials)

    OAuth2 credentials



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/cal4near.rb', line 151

def self.authorize
  client_id = Google::Auth::ClientId.from_file CREDENTIALS_PATH
  token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH
  authorizer = Google::Auth::UserAuthorizer.new client_id, SCOPE, token_store
  user_id = "default"
  credentials = authorizer.get_credentials user_id
  if credentials.nil?
    url = authorizer.get_authorization_url base_url: OOB_URI
    puts "Open the following URL in the browser and enter the " \
       "resulting code after authorization:\n" + url
    code = gets
    credentials = authorizer.get_and_store_credentials_from_code(
      user_id: user_id, code: code, base_url: OOB_URI
    )
  end
  credentials
end

.events(start_date, end_date) ⇒ Array

カレンダーに登録されているイベントを取得

Parameters:

  • start_date (DateTime)

    対象期間の開始日時

  • end_date (DateTime)

    対象期間の終了日時

Returns:

  • (Array)

    Google::Apis::CalendarV3::Eventのリスト



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/cal4near.rb', line 34

def self.events(start_date, end_date)
  service = Google::Apis::CalendarV3::CalendarService.new
  service.client_options.application_name = APPLICATION_NAME
  service.authorization = authorize
  service.list_events(
    "primary",
    single_events: true,
    order_by: "startTime",
    time_min: start_date.rfc3339,
    time_max: end_date.rfc3339
  ).items
end

.format(times_info, is_free = true) ⇒ Object

Parameters:

  • free_busy_times (Hash)


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/cal4near.rb', line 112

def self.format(times_info, is_free = true)
  result = times_info
  wdays = %w(      )
  # 出力
  date_time_info = result.map do |date, times|
    min_time = max_time = nil
    spans = []
    times.each do |time, info|
      time = DateTime.parse(time)
      min_time ||= time
      max_time = time
      if (is_free && info[:free]) || (!is_free && !info[:free])
        next
      else
        if min_time && max_time && min_time < max_time
          spans << "#{min_time.strftime("%-H:%M")}-#{max_time.strftime("%-H:%M")}"
        end
        min_time = max_time = nil
      end
    end

    if min_time && max_time && min_time < max_time
      spans << "#{min_time.strftime("%-H:%M")}-#{max_time.strftime("%-H:%M")}"
    end

    tmp_date = Date.parse(date)
    spans_text = spans.empty? ? "" : " #{spans.join(", ")}"
    "#{tmp_date.strftime("%Y/%m/%d")}(#{wdays[tmp_date.wday]})#{spans_text}"
  end

  date_time_info.join("\n")
end

.free_busy_times(start_date = START_DATE, end_date = END_DATE, start_hour = START_HOUR, end_hour = END_HOUR, max_date_count = 100) ⇒ Hash

カレンダーの空き情報を取得

Examples:

返り値のサンプルは以下

"2022-03-21"=> {"2022-03-21 09:00"=>{:free=>true}

Returns:

  • (Hash)


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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/cal4near.rb', line 54

def self.free_busy_times(
  start_date = START_DATE,
  end_date = END_DATE,
  start_hour = START_HOUR,
  end_hour = END_HOUR,
  max_date_count = 100
)
  busy_list = []
  events(start_date, end_date).each do |event|
    # start endが両方ともdate型の場合は終日の予定
    is_all_date = (event.start.date && event.end.date)

    # [デバッグ用]カレンダーイベントの情報を出力する
    # stdout_calendar_info(event, is_all_date)

    unless is_all_date
      busy_list << {
        start: event.start.date_time,
        end: event.end.date_time
      }
    end
  end

  # puts "Free time:"

  result = {}
  (start_date.to_date..end_date.to_date).each.with_index(1) do |date, i|
    break if i > max_date_count

    result[date.strftime(DATE_FORMAT)] ||= {} # YYYY-MM-DD

    start_work_time = Time.new(date.year, date.month, date.day, start_hour, 0, 0)
    end_work_time = Time.new(date.year, date.month, date.day, end_hour, 0, 0)

    step_secound = 60*60
    start_work_time.to_i.step(end_work_time.to_i, step_secound).each_cons(2) do |c_time_int, n_time_int|
      current_time = Time.at(c_time_int)
      next_time = Time.at(n_time_int)

      # 現時刻より前はスキップ
      next if current_time.to_datetime < DateTime.now

      date_key = date.strftime(DATE_FORMAT)
      time_key = current_time.strftime(DATE_TIME_FORMAT)
      result[date_key][time_key] = { free: true }

      busy_list.each do |busy|
        if current_time.to_datetime < busy[:end] && busy[:start] < next_time.to_datetime
          result[date_key][time_key][:free] = false
          break
        end
      end
    end
  end
  result
end