Skip to content

Commit

Permalink
Merge pull request #67 from pivotal/master
Browse files Browse the repository at this point in the history
Add Freebusy query support
  • Loading branch information
szich committed Mar 23, 2015
2 parents 1eb5717 + 930d19e commit d21bd2c
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 3 deletions.
6 changes: 4 additions & 2 deletions lib/google/calendar.rb
Expand Up @@ -6,7 +6,7 @@ module Google
#
class Calendar

attr_reader :id, :connection
attr_reader :id, :connection, :summary

#
# Setup and connect to the specified Google Calendar.
Expand Down Expand Up @@ -246,7 +246,9 @@ def encode_time(time) #:nodoc:
def event_lookup(query_string = '') #:nodoc:
begin
response = send_events_request(query_string, :get)
events = Event.build_from_google_feed( JSON.parse(response.body) , self) || []
parsed_json = JSON.parse(response.body)
@summary = parsed_json['summary']
events = Event.build_from_google_feed(parsed_json, self) || []
return events if events.empty?
events.length > 1 ? events : [events[0]]
rescue Google::HTTPNotFound
Expand Down
4 changes: 3 additions & 1 deletion lib/google/event.rb
Expand Up @@ -29,7 +29,7 @@ module Google
#
class Event
attr_reader :raw, :html_link, :status
attr_accessor :id, :title, :location, :calendar, :quickadd, :transparency, :attendees, :description, :reminders, :recurrence, :visibility
attr_accessor :id, :title, :location, :calendar, :quickadd, :transparency, :attendees, :description, :reminders, :recurrence, :visibility, :creator_name

#
# Create a new event, and optionally set it's attributes.
Expand Down Expand Up @@ -61,6 +61,7 @@ def initialize(params = {})
self.visibility = params[:visibility]
self.transparency = params[:transparency]
self.all_day = params[:all_day] if params[:all_day]
self.creator_name = params[:creator]['displayName'] if params[:creator]
end

#
Expand Down Expand Up @@ -365,6 +366,7 @@ def self.new_from_feed(e, calendar) #:nodoc:
:title => e['summary'],
:description => e['description'],
:location => e['location'],
:creator => e['creator'],
:start_time => Event.parse_json_time(e['start']),
:end_time => Event.parse_json_time(e['end']),
:transparency => e['transparency'],
Expand Down
76 changes: 76 additions & 0 deletions lib/google/freebusy.rb
@@ -0,0 +1,76 @@
require 'time'
require 'json'

module Google

#
# Freebusy returns free/busy information for a set of calendars
#
class Freebusy

attr_reader :connection

#
# Setup and query the free/busy status of a collection of calendars.
#
# The +params+ parameter accepts
# * :client_id => the client ID that you received from Google after registering your application with them (https://console.developers.google.com/). REQUIRED
# * :client_secret => the client secret you received from Google after registering your application with them. REQUIRED
# * :redirect_url => the url where your users will be redirected to after they have successfully permitted access to their calendars. Use 'urn:ietf:wg:oauth:2.0:oob' if you are using an 'application'" REQUIRED
# * :refresh_token => if a user has already given you access to their calendars, you can specify their refresh token here and you will be 'logged on' automatically (i.e. they don't need to authorize access again). OPTIONAL
#
# See Readme.rdoc or readme_code.rb for an explication on the OAuth2 authorization process.
#
def initialize(params={}, connection=nil)
@connection = connection || Connection.new(
:client_id => params[:client_id],
:client_secret => params[:client_secret],
:refresh_token => params[:refresh_token],
:redirect_url => params[:redirect_url]
)
end

#
# Find the busy times of the supplied calendar IDs, within the boundaries
# of the supplied start_time and end_time
#
# The arguments supplied are
# * calendar_ids => array of Google calendar IDs as strings
# * start_time => a Time object, the start of the interval for the query.
# * end_time => a Time object, the end of the interval for the query.
#
def query(calendar_ids, start_time, end_time)
query_content = json_for_query(calendar_ids, start_time, end_time)
response = @connection.send("/freeBusy", :post, query_content)

return nil if response.status != 200 || response.body.empty?

parse_freebusy_response(response.body)
end

private

#
# Prepare the JSON
#
def json_for_query(calendar_ids, start_time, end_time)
{}.tap{ |obj|
obj[:items] = calendar_ids.map {|id| Hash[:id, id] }
obj[:timeMin] = start_time.utc.iso8601
obj[:timeMax] = end_time.utc.iso8601
}.to_json
end

def parse_freebusy_response(response_body)
query_result = JSON.parse(response_body)

return nil unless query_result['calendars'].is_a? Hash

query_result['calendars'].each_with_object({}) do |(calendar_id, value), result|
result[calendar_id] = value['busy'] || []
end
end

end

end
1 change: 1 addition & 0 deletions lib/google_calendar.rb
Expand Up @@ -5,4 +5,5 @@ module Google
require 'google/calendar_list_entry'
require 'google/connection'
require 'google/event'
require 'google/freebusy'
end
22 changes: 22 additions & 0 deletions test/mocks/freebusy_query.json
@@ -0,0 +1,22 @@
{
"timeMin": "2015-03-06T00:00:00.000Z",
"timeMax": "2015-03-06T23:59:59.000Z",
"calendars": {
"busy-calendar-id": {
"busy": [
{
"start": "2015-03-06T10:00:00Z",
"end": "2015-03-06T11:00:00Z"
},
{
"start": "2015-03-06T11:30:00Z",
"end": "2015-03-06T11:30:00Z"
}
]
},
"not-busy-calendar-id": {
"busy": [
]
}
}
}
49 changes: 49 additions & 0 deletions test/test_google_calendar.rb
Expand Up @@ -239,6 +239,12 @@ class TestGoogleCalendar < Minitest::Test
assert_equal event.title, 'New Event Update when id is NIL'
end

should "provide the calendar summary" do
@client_mock.stubs(:body).returns( get_mock_body("events.json") )
@calendar.events
assert_equal 'My Events Calendar', @calendar.summary
end

end # Logged on context

end # Connected context
Expand Down Expand Up @@ -289,6 +295,13 @@ class TestGoogleCalendar < Minitest::Test
end
end

context "#creator_name" do
should "include name" do
event = Event.new :creator => {'displayName' => 'Someone', 'email' => 'someone@example.com'}
assert_equal 'Someone', event.creator_name
end
end

context "transparency" do
should "be transparent" do
@event = Event.new(:transparency => true)
Expand Down Expand Up @@ -457,6 +470,42 @@ class TestGoogleCalendar < Minitest::Test

end

context "a freebusy query" do

setup do
@client_mock = setup_mock_client

@client_id = "671053090364-ntifn8rauvhib9h3vnsegi6dhfglk9ue.apps.googleusercontent.com"
@client_secret = "roBgdbfEmJwPgrgi2mRbbO-f"
@refresh_token = "1/eiqBWx8aj-BsdhwvlzDMFOUN1IN_HyThvYTujyksO4c"

@freebusy = Google::Freebusy.new(
:client_id => @client_id,
:client_secret => @client_secret,
:redirect_url => "urn:ietf:wg:oauth:2.0:oob",
:refresh_token => @refresh_token
)

@client_mock.stubs(:body).returns(get_mock_body("freebusy_query.json"))

@calendar_ids = ['busy-calendar-id', 'not-busy-calendar-id']
@start_time = Time.new(2015, 3, 6, 0, 0, 0)
@end_time = Time.new(2015, 3, 6, 23, 59, 59)
end

should "return a hash with keys of the supplied calendar ids" do
assert_equal ['busy-calendar-id', 'not-busy-calendar-id'], @freebusy.query(@calendar_ids, @start_time, @end_time).keys
end

should "returns the busy times for each calendar supplied" do
freebusy_result = @freebusy.query(@calendar_ids, @start_time, @end_time)

assert_equal ({'start' => '2015-03-06T10:00:00Z', 'end' => '2015-03-06T11:00:00Z' }), freebusy_result['busy-calendar-id'].first
assert_equal ({'start' => '2015-03-06T11:30:00Z', 'end' => '2015-03-06T11:30:00Z' }), freebusy_result['busy-calendar-id'].last
assert_equal [], freebusy_result['not-busy-calendar-id']
end
end

protected

def get_mock_body(name)
Expand Down

0 comments on commit d21bd2c

Please sign in to comment.