view release on metacpan or search on metacpan
t/unit/Test/Google/RestApi/TasksApi1.pm
t/unit/Test/Google/RestApi/TasksApi1.pm.exchanges
t/unit/Test/Google/RestApi/TasksApi1/Task.pm
t/unit/Test/Google/RestApi/TasksApi1/Task.pm.exchanges
t/unit/Test/Google/RestApi/TasksApi1/TaskList.pm
t/unit/Test/Google/RestApi/TasksApi1/TaskList.pm.exchanges
t/unit/Test/Google/RestApi/Types.pm
t/unit/Test/Google/RestApi/Utils.pm
t/unit/Test/Google/RestApi/Utils.pm.exchanges
tutorial/99_delete_all.pl
tutorial/calendar/10_calendar_basics.pl
tutorial/calendar/20_events.pl
tutorial/calendar/30_sharing.pl
tutorial/docs/10_document_basics.pl
tutorial/docs/20_batch_updates.pl
tutorial/docs/30_structure.pl
tutorial/drive/10_file_operations.pl
tutorial/drive/20_comments.pl
tutorial/gmail/10_gmail_basics.pl
tutorial/gmail/20_send_and_read.pl
tutorial/gmail/30_threads_and_drafts.pl
tutorial/lib/Tutorial/Setup.pm
tutorial/lib/Tutorial/Utils.pm
> # --- Sheets API ---
> use Google::RestApi::SheetsApi4;
> $sheets = Google::RestApi::SheetsApi4->new(api => $rest_api);
> $spreadsheet = $sheets->open_spreadsheet(name => 'My Sheet');
> $worksheet = $spreadsheet->open_worksheet(name => 'Sheet1');
> @values = $worksheet->col('A');
> $worksheet->row(1, ['Name', 'Email', 'Phone']);
>
> # --- Calendar API ---
> use Google::RestApi::CalendarApi3;
> $calendar_api = Google::RestApi::CalendarApi3->new(api => $rest_api);
> $calendar = $calendar_api->create_calendar(summary => 'Team Events');
> $event = $calendar->event();
> $event->create(
> summary => 'Meeting',
> start => { dateTime => '2026-03-01T10:00:00-05:00' },
> end => { dateTime => '2026-03-01T11:00:00-05:00' },
> );
>
> # --- Gmail API ---
> use Google::RestApi::GmailApi1;
> $gmail = Google::RestApi::GmailApi1->new(api => $rest_api);
> $gmail->send_message(
bin/google_restapi_oauth_token_creator view on Meta::CPAN
google_restapi:
auth:
class: OAuth2Client
client_id: <client-id-from-google>
client_secret: <client-secret-from-google>
token_file: <filename-for-the-stored-token> # filename only, not a path
scope:
- https://www.googleapis.com/auth/drive
- https://www.googleapis.com/auth/spreadsheets
# add further scopes as needed:
# - https://www.googleapis.com/auth/calendar
# - https://www.googleapis.com/auth/documents
# - https://www.googleapis.com/auth/gmail.modify
# - https://www.googleapis.com/auth/tasks
other_app:
some_key: some_value
# or, without the google_restapi wrapper (root-level config):
---
auth:
class: OAuth2Client
lib/Google/RestApi.pm view on Meta::CPAN
# --- Sheets API ---
use Google::RestApi::SheetsApi4;
$sheets = Google::RestApi::SheetsApi4->new(api => $rest_api);
$spreadsheet = $sheets->open_spreadsheet(name => 'My Sheet');
$worksheet = $spreadsheet->open_worksheet(name => 'Sheet1');
@values = $worksheet->col('A');
$worksheet->row(1, ['Name', 'Email', 'Phone']);
# --- Calendar API ---
use Google::RestApi::CalendarApi3;
$calendar_api = Google::RestApi::CalendarApi3->new(api => $rest_api);
$calendar = $calendar_api->create_calendar(summary => 'Team Events');
$event = $calendar->event();
$event->create(
summary => 'Meeting',
start => { dateTime => '2026-03-01T10:00:00-05:00' },
end => { dateTime => '2026-03-01T11:00:00-05:00' },
);
# --- Gmail API ---
use Google::RestApi::GmailApi1;
$gmail = Google::RestApi::GmailApi1->new(api => $rest_api);
$gmail->send_message(
lib/Google/RestApi/CalendarApi3.pm view on Meta::CPAN
use Google::RestApi::Setup;
use Readonly;
use URI;
use aliased 'Google::RestApi::CalendarApi3::Calendar';
use aliased 'Google::RestApi::CalendarApi3::CalendarList';
use aliased 'Google::RestApi::CalendarApi3::Colors';
use aliased 'Google::RestApi::CalendarApi3::Settings';
Readonly our $Calendar_Endpoint => 'https://www.googleapis.com/calendar/v3';
Readonly our $Calendar_Id => '[a-zA-Z0-9._@-]+';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
api => HasApi,
endpoint => Str, { default => $Calendar_Endpoint },
],
lib/Google/RestApi/CalendarApi3.pm view on Meta::CPAN
uri => Str, { optional => 1 },
_extra_ => slurpy HashRef,
],
);
my $p = named_extra($check->(@_));
my $uri = "$self->{endpoint}/";
$uri .= delete $p->{uri} if defined $p->{uri};
return $self->{api}->api(%$p, uri => $uri);
}
sub calendar {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
id => Str,
],
);
my $p = $check->(@_);
return Calendar->new(calendar_api => $self, %$p);
}
sub calendar_list {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
id => Str, { optional => 1 },
],
);
my $p = $check->(@_);
return CalendarList->new(calendar_api => $self, %$p);
}
sub colors { Colors->new(calendar_api => shift); }
sub settings {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
id => Str, { optional => 1 },
],
);
my $p = $check->(@_);
return Settings->new(calendar_api => $self, %$p);
}
sub create_calendar {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
summary => Str,
_extra_ => slurpy HashRef,
],
);
my $p = named_extra($check->(@_));
my %content = (
summary => delete $p->{summary},
);
DEBUG("Creating calendar '$content{summary}'");
my $result = $self->api(
uri => 'calendars',
method => 'post',
content => \%content,
);
return Calendar->new(calendar_api => $self, id => $result->{id});
}
sub list_calendars {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
max_pages => Int, { default => 0 },
page_callback => CodeRef, { optional => 1 },
params => HashRef, { default => {} },
],
);
my $p = $check->(@_);
return paginated_list(
api => $self,
uri => 'users/me/calendarList',
result_key => 'items',
default_fields => 'items(id, summary)',
max_pages => $p->{max_pages},
params => $p->{params},
($p->{page_callback} ? (page_callback => $p->{page_callback}) : ()),
);
}
sub freebusy {
my $self = shift;
lib/Google/RestApi/CalendarApi3.pm view on Meta::CPAN
# Create the REST API instance
my $rest_api = Google::RestApi->new(
config_file => '/path/to/config.yaml',
);
# Create the Calendar API instance
my $cal_api = Google::RestApi::CalendarApi3->new(api => $rest_api);
=head2 Working with Calendars
# Create a new calendar
my $calendar = $cal_api->create_calendar(summary => 'My New Calendar');
# Get an existing calendar (e.g. primary)
my $primary = $cal_api->calendar(id => 'primary');
my $metadata = $primary->get();
# Update calendar metadata
$primary->update(summary => 'Updated Name', description => 'New description');
# List all calendars for the user
my @calendars = $cal_api->list_calendars();
=head2 Working with Events
my $calendar = $cal_api->calendar(id => 'primary');
# Create a timed event
my $event = $calendar->event()->create(
summary => 'Team Meeting',
start => { dateTime => '2026-03-01T10:00:00-05:00' },
end => { dateTime => '2026-03-01T11:00:00-05:00' },
);
# Quick add an event using natural language
my $quick = $calendar->event()->quick_add(text => 'Lunch with Bob tomorrow at noon');
# List events
my @events = $calendar->events();
# Get/update/delete an event
my $details = $event->get();
$event->update(summary => 'Updated Meeting');
$event->delete();
=head2 Access Control (ACL)
# List ACL rules on a calendar
my @rules = $calendar->acl_rules();
# Create an ACL rule
my $acl = $calendar->acl()->create(
role => 'reader',
scope_type => 'user',
scope_value => 'user@example.com',
);
# Delete an ACL rule
$acl->delete();
=head2 Calendar List, Colors, and Settings
# Calendar list (user's view of calendars)
my $cl = $cal_api->calendar_list(id => 'primary');
my $info = $cl->get();
# Get available colors
my $colors = $cal_api->colors();
my $all = $colors->get();
# Get a setting
my $setting = $cal_api->settings(id => 'timezone');
my $value = $setting->value();
=head1 DESCRIPTION
Google::RestApi::CalendarApi3 provides a Perl interface to the Google Calendar API V3.
It enables calendar management including:
=over 4
=item * Calendar CRUD operations (create, get, update, delete)
=item * Event management (create, get, update, delete, quick add)
=item * Access control (ACL) management
=item * Calendar list management (user's view of calendars)
=item * Colors and settings (read-only)
=item * Free/busy queries
=back
It is assumed that you are familiar with the Google Calendar API:
L<https://developers.google.com/calendar/api/v3/reference>
=head2 Architecture
The API uses a hierarchical object model where child objects delegate API calls
to their parent:
CalendarApi3 (top-level)
|-- calendar(id => ...) -> Calendar
| |-- event(id => ...) -> Event
| |-- acl(id => ...) -> Acl
|-- calendar_list(id => ...) -> CalendarList
|-- colors() -> Colors
|-- settings(id => ...) -> Settings
Each object provides CRUD operations appropriate to its resource type.
=head1 NAVIGATION
=over
=item * L<Google::RestApi::CalendarApi3> - This module (top-level Calendar API)
lib/Google/RestApi/CalendarApi3.pm view on Meta::CPAN
=over
=item * C<uri> <string>: Path segments to append to the Calendar endpoint.
=item * C<%args>: Additional arguments passed to L<Google::RestApi>'s api() (content, params, method, etc).
=back
Returns the response hash from the Google API.
=head2 calendar(%args)
Returns a Calendar object for the given calendar ID.
my $cal = $cal_api->calendar(id => 'primary');
my $cal = $cal_api->calendar(id => 'user@gmail.com');
%args consists of:
=over
=item * C<id> <string>: Required. The calendar ID (e.g. 'primary' or an email address).
=back
=head2 calendar_list(%args)
Returns a CalendarList object for managing the user's view of calendars.
my $cl = $cal_api->calendar_list(id => 'primary');
%args consists of:
=over
=item * C<id> <string>: Optional. The calendar ID. Required for get/update/delete.
=back
=head2 colors()
Returns a Colors object for querying available calendar and event colors.
my $colors = $cal_api->colors();
my $all = $colors->get();
=head2 settings(%args)
Returns a Settings object for querying user settings.
my $setting = $cal_api->settings(id => 'timezone');
my $value = $setting->value();
%args consists of:
=over
=item * C<id> <string>: Optional. The setting ID. Required for get/value.
=back
=head2 create_calendar(%args)
Creates a new calendar.
my $cal = $cal_api->create_calendar(summary => 'My Calendar');
%args consists of:
=over
=item * C<summary> <string>: Required. The name for the calendar.
=back
Returns a Calendar object for the created calendar.
=head2 list_calendars(%args)
Lists all calendars visible to the user.
my @calendars = $cal_api->list_calendars();
my @calendars = $cal_api->list_calendars(max_pages => 2);
C<max_pages> limits the number of pages fetched (default 0 = unlimited).
Supports C<page_callback>, see L<Google::RestApi/PAGE CALLBACKS>.
Returns a list of calendar hashrefs with id and summary.
=head2 freebusy(%args)
Queries free/busy information for a set of calendars.
my $result = $cal_api->freebusy(
time_min => '2026-03-01T00:00:00Z',
time_max => '2026-03-02T00:00:00Z',
items => [{ id => 'primary' }],
);
%args consists of:
=over
=item * C<time_min> <string>: Required. Start of the time range (RFC3339).
=item * C<time_max> <string>: Required. End of the time range (RFC3339).
=item * C<items> <arrayref>: Required. List of calendar IDs to query.
=back
=head2 rest_api()
Returns the underlying L<Google::RestApi> instance.
=head1 SEE ALSO
=over
lib/Google/RestApi/CalendarApi3.pm view on Meta::CPAN
=item * L<Google::RestApi::DriveApi3> - Google Drive API (related module)
=item * L<Google::RestApi::SheetsApi4> - Google Sheets API (related module)
=item * L<Google::RestApi::GmailApi1> - Google Gmail API (related module)
=item * L<Google::RestApi::TasksApi1> - Google Tasks API (related module)
=item * L<Google::RestApi::DocsApi1> - Google Docs API (related module)
=item * L<https://developers.google.com/calendar/api/v3/reference> - Google Calendar API Reference
=back
=head1 AUTHORS
=over
=item
Robin Murray mvsjes@cpan.org
lib/Google/RestApi/CalendarApi3/Acl.pm view on Meta::CPAN
use Google::RestApi::Setup;
use parent 'Google::RestApi::SubResource';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
calendar => HasApi,
id => Str, { optional => 1 },
],
);
return bless $check->(@_), $class;
}
sub _uri_base { 'acl' }
sub _parent_accessor { 'calendar' }
sub _resource_name { 'ACL' }
sub create {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
role => Str,
scope_type => Str,
scope_value => Str, { optional => 1 },
lib/Google/RestApi/CalendarApi3/Acl.pm view on Meta::CPAN
my $p = named_extra($check->(@_));
my %content = (
role => delete $p->{role},
scope => {
type => delete $p->{scope_type},
},
);
$content{scope}{value} = delete $p->{scope_value} if defined $p->{scope_value};
DEBUG(sprintf("Creating ACL rule on calendar '%s'", $self->calendar()->calendar_id()));
my $result = $self->calendar()->api(
uri => 'acl',
method => 'post',
content => \%content,
);
return ref($self)->new(calendar => $self->calendar(), id => $result->{id});
}
sub get {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
fields => Str, { optional => 1 },
],
);
lib/Google/RestApi/CalendarApi3/Acl.pm view on Meta::CPAN
],
);
my $p = named_extra($check->(@_));
$self->require_id('update');
my %content = (
role => delete $p->{role},
);
DEBUG(sprintf("Updating ACL rule '%s' on calendar '%s'", $self->{id}, $self->calendar()->calendar_id()));
return $self->api(
method => 'patch',
content => \%content,
);
}
sub delete {
my $self = shift;
$self->require_id('delete');
DEBUG(sprintf("Deleting ACL rule '%s' from calendar '%s'", $self->{id}, $self->calendar()->calendar_id()));
return $self->api(method => 'delete');
}
sub acl_id { shift->{id}; }
sub calendar { shift->{calendar}; }
1;
__END__
=head1 NAME
Google::RestApi::CalendarApi3::Acl - ACL (Access Control) object for Google Calendar.
=head1 SYNOPSIS
# Get an ACL rule
my $acl = $calendar->acl(id => 'rule_id');
my $details = $acl->get();
# Create a new ACL rule
my $new_acl = $calendar->acl()->create(
role => 'reader',
scope_type => 'user',
scope_value => 'user@example.com',
);
# Update ACL rule
$acl->update(role => 'writer');
# Delete ACL rule
$acl->delete();
lib/Google/RestApi/CalendarApi3/Acl.pm view on Meta::CPAN
Updates the ACL rule role. Requires ACL ID.
=head2 delete()
Deletes the ACL rule. Requires ACL ID.
=head2 acl_id()
Returns the ACL rule ID.
=head2 calendar()
Returns the parent Calendar object.
=head1 AUTHORS
=over
=item
Robin Murray mvsjes@cpan.org
lib/Google/RestApi/CalendarApi3/Calendar.pm view on Meta::CPAN
use parent 'Google::RestApi::SubResource';
use aliased 'Google::RestApi::CalendarApi3::Event';
use aliased 'Google::RestApi::CalendarApi3::Acl';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
calendar_api => HasApi,
id => Str,
],
);
return bless $check->(@_), $class;
}
sub _uri_base { 'calendars' }
sub _parent_accessor { 'calendar_api' }
sub get {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
fields => Str, { optional => 1 },
params => HashRef, { default => {} },
],
);
lib/Google/RestApi/CalendarApi3/Calendar.pm view on Meta::CPAN
],
);
my $p = named_extra($check->(@_));
my %content;
$content{summary} = delete $p->{summary} if defined $p->{summary};
$content{description} = delete $p->{description} if defined $p->{description};
$content{location} = delete $p->{location} if defined $p->{location};
$content{timeZone} = delete $p->{time_zone} if defined $p->{time_zone};
DEBUG(sprintf("Updating calendar '%s'", $self->{id}));
return $self->api(
method => 'put',
content => \%content,
);
}
sub delete {
my $self = shift;
DEBUG(sprintf("Deleting calendar '%s'", $self->{id}));
return $self->api(method => 'delete');
}
sub clear {
my $self = shift;
DEBUG(sprintf("Clearing calendar '%s'", $self->{id}));
return $self->api(uri => 'clear', method => 'post');
}
sub event {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
id => Str, { optional => 1 },
],
);
my $p = $check->(@_);
return Event->new(calendar => $self, %$p);
}
sub events {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
fields => Str, { optional => 1 },
max_pages => Int, { default => 0 },
page_callback => CodeRef, { optional => 1 },
lib/Google/RestApi/CalendarApi3/Calendar.pm view on Meta::CPAN
sub acl {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
id => Str, { optional => 1 },
],
);
my $p = $check->(@_);
return Acl->new(calendar => $self, %$p);
}
sub acl_rules {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
fields => Str, { optional => 1 },
max_pages => Int, { default => 0 },
page_callback => CodeRef, { optional => 1 },
lib/Google/RestApi/CalendarApi3/Calendar.pm view on Meta::CPAN
api => $self,
uri => 'acl',
result_key => 'items',
default_fields => 'items(id, role, scope)',
max_pages => $p->{max_pages},
params => $p->{params},
($p->{page_callback} ? (page_callback => $p->{page_callback}) : ()),
);
}
sub calendar_id { shift->{id}; }
sub calendar_api { shift->{calendar_api}; }
1;
__END__
=head1 NAME
Google::RestApi::CalendarApi3::Calendar - Calendar object for Google Calendar.
=head1 SYNOPSIS
my $calendar = $cal_api->calendar(id => 'primary');
# Get calendar metadata
my $metadata = $calendar->get();
# Update calendar
$calendar->update(summary => 'New Name', description => 'New description');
# Delete calendar
$calendar->delete();
# Clear all events (primary calendar only)
$calendar->clear();
# Events
my @events = $calendar->events();
my $event = $calendar->event(id => 'event_id');
$calendar->event()->create(
summary => 'Meeting',
start => { dateTime => '2026-03-01T10:00:00Z' },
end => { dateTime => '2026-03-01T11:00:00Z' },
);
# ACL rules
my @rules = $calendar->acl_rules();
my $acl = $calendar->acl(id => 'rule_id');
=head1 DESCRIPTION
Represents a Google Calendar with full CRUD operations, event management,
and access control.
=head1 METHODS
=head2 get(fields => $fields, params => \%params)
Retrieves calendar metadata.
=head2 update(summary => $name, description => $desc, ...)
Updates calendar metadata. Supports summary, description, location,
and time_zone parameters.
=head2 delete()
Permanently deletes the calendar.
=head2 clear()
Clears all events from a calendar. Only works on the primary calendar.
=head2 event(id => $id)
Returns an Event object. Without id, can be used to create new events.
=head2 events(max_pages => $n, page_callback => $coderef)
Lists all events on the calendar. C<max_pages> limits the number of pages
fetched (default 0 = unlimited). Supports C<page_callback>,
see L<Google::RestApi/PAGE CALLBACKS>.
=head2 acl(id => $id)
Returns an Acl object. Without id, can be used to create new ACL rules.
=head2 acl_rules(max_pages => $n, page_callback => $coderef)
Lists all ACL rules on the calendar. C<max_pages> limits the number of pages
fetched (default 0 = unlimited). Supports C<page_callback>,
see L<Google::RestApi/PAGE CALLBACKS>.
=head2 calendar_id()
Returns the calendar ID.
=head2 calendar_api()
Returns the parent CalendarApi3 object.
=head1 AUTHORS
=over
=item
Robin Murray mvsjes@cpan.org
lib/Google/RestApi/CalendarApi3/CalendarList.pm view on Meta::CPAN
use Google::RestApi::Setup;
use parent 'Google::RestApi::SubResource';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
calendar_api => HasApi,
id => Str, { optional => 1 },
],
);
return bless $check->(@_), $class;
}
sub _uri_base { 'users/me/calendarList' }
sub _parent_accessor { 'calendar_api' }
sub get {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
fields => Str, { optional => 1 },
],
);
my $p = $check->(@_);
lib/Google/RestApi/CalendarApi3/CalendarList.pm view on Meta::CPAN
id => Str,
_extra_ => slurpy HashRef,
],
);
my $p = named_extra($check->(@_));
my %content = (
id => delete $p->{id},
);
DEBUG(sprintf("Inserting calendar '%s' into calendar list", $content{id}));
my $result = $self->calendar_api()->api(
uri => 'users/me/calendarList',
method => 'post',
content => \%content,
);
return ref($self)->new(calendar_api => $self->calendar_api(), id => $result->{id});
}
sub update {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
summary_override => Str, { optional => 1 },
color_id => Str, { optional => 1 },
hidden => Bool, { optional => 1 },
lib/Google/RestApi/CalendarApi3/CalendarList.pm view on Meta::CPAN
my $p = named_extra($check->(@_));
$self->require_id('update');
my %content;
$content{summaryOverride} = delete $p->{summary_override} if defined $p->{summary_override};
$content{colorId} = delete $p->{color_id} if defined $p->{color_id};
$content{hidden} = delete $p->{hidden} ? JSON::MaybeXS::true() : JSON::MaybeXS::false() if defined $p->{hidden};
$content{selected} = delete $p->{selected} ? JSON::MaybeXS::true() : JSON::MaybeXS::false() if defined $p->{selected};
DEBUG(sprintf("Updating calendar list entry '%s'", $self->{id}));
return $self->api(
method => 'patch',
content => \%content,
);
}
sub delete {
my $self = shift;
$self->require_id('delete');
DEBUG(sprintf("Deleting calendar list entry '%s'", $self->{id}));
return $self->api(method => 'delete');
}
sub calendar_list_id { shift->{id}; }
sub calendar_api { shift->{calendar_api}; }
1;
__END__
=head1 NAME
Google::RestApi::CalendarApi3::CalendarList - CalendarList object for Google Calendar.
=head1 SYNOPSIS
# Get a calendar list entry
my $cl = $cal_api->calendar_list(id => 'primary');
my $info = $cl->get();
# Insert a calendar into the user's list
my $cl = $cal_api->calendar_list()->insert(id => 'calendar_id@group.calendar.google.com');
# Update display settings
$cl->update(summary_override => 'My Custom Name', color_id => '7');
# Remove from the user's list
$cl->delete();
=head1 DESCRIPTION
Represents an entry in the user's calendar list. This manages the user's
view and display settings for calendars, not the calendars themselves.
=head1 METHODS
=head2 get(fields => $fields)
Gets calendar list entry details. Requires calendar list ID.
=head2 insert(id => $calendar_id)
Inserts a calendar into the user's calendar list.
=head2 update(summary_override => $name, color_id => $id, ...)
Updates display settings. Requires calendar list ID.
=head2 delete()
Removes the calendar from the user's list. Requires calendar list ID.
=head2 calendar_list_id()
Returns the calendar list entry ID.
=head2 calendar_api()
Returns the parent CalendarApi3 object.
=head1 AUTHORS
=over
=item
Robin Murray mvsjes@cpan.org
lib/Google/RestApi/CalendarApi3/Colors.pm view on Meta::CPAN
our $VERSION = '2.2.2';
use Google::RestApi::Setup;
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
calendar_api => HasApi,
],
);
return bless $check->(@_), $class;
}
sub api {
my $self = shift;
return $self->calendar_api()->api(uri => 'colors', @_);
}
sub get {
my $self = shift;
return $self->api();
}
sub calendar_colors {
my $self = shift;
return $self->get()->{calendar};
}
sub event_colors {
my $self = shift;
return $self->get()->{event};
}
sub calendar_api { shift->{calendar_api}; }
1;
__END__
=head1 NAME
Google::RestApi::CalendarApi3::Colors - Colors information for Google Calendar.
=head1 SYNOPSIS
my $colors = $cal_api->colors();
# Get all color definitions
my $all = $colors->get();
# Get just calendar colors
my $cal_colors = $colors->calendar_colors();
# Get just event colors
my $evt_colors = $colors->event_colors();
=head1 DESCRIPTION
Provides access to the available color definitions for calendars and events.
=head1 METHODS
=head2 get()
Gets all color definitions.
=head2 calendar_colors()
Returns calendar color definitions.
=head2 event_colors()
Returns event color definitions.
=head2 calendar_api()
Returns the parent CalendarApi3 object.
=head1 AUTHORS
=over
=item
Robin Murray mvsjes@cpan.org
lib/Google/RestApi/CalendarApi3/Event.pm view on Meta::CPAN
use Google::RestApi::Setup;
use parent 'Google::RestApi::SubResource';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
calendar => HasApi,
id => Str, { optional => 1 },
],
);
return bless $check->(@_), $class;
}
sub _uri_base { 'events' }
sub _parent_accessor { 'calendar' }
sub create {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
summary => Str,
start => HashRef,
end => HashRef,
description => Str, { optional => 1 },
lib/Google/RestApi/CalendarApi3/Event.pm view on Meta::CPAN
my %content = (
summary => delete $p->{summary},
start => delete $p->{start},
end => delete $p->{end},
);
$content{description} = delete $p->{description} if defined $p->{description};
$content{location} = delete $p->{location} if defined $p->{location};
$content{attendees} = delete $p->{attendees} if defined $p->{attendees};
DEBUG(sprintf("Creating event '%s' on calendar '%s'", $content{summary}, $self->calendar()->calendar_id()));
my $result = $self->calendar()->api(
uri => 'events',
method => 'post',
content => \%content,
);
return ref($self)->new(calendar => $self->calendar(), id => $result->{id});
}
sub get {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
fields => Str, { optional => 1 },
],
);
lib/Google/RestApi/CalendarApi3/Event.pm view on Meta::CPAN
sub quick_add {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
text => Str,
],
);
my $p = $check->(@_);
DEBUG(sprintf("Quick adding event on calendar '%s': %s", $self->calendar()->calendar_id(), $p->{text}));
my $result = $self->calendar()->api(
uri => 'events/quickAdd',
method => 'post',
params => { text => $p->{text} },
);
return ref($self)->new(calendar => $self->calendar(), id => $result->{id});
}
sub instances {
my $self = shift;
state $check = signature(
bless => !!0,
named => [
fields => Str, { optional => 1 },
max_pages => Int, { default => 0 },
page_callback => CodeRef, { optional => 1 },
lib/Google/RestApi/CalendarApi3/Event.pm view on Meta::CPAN
state $check = signature(
bless => !!0,
named => [
destination => Str,
],
);
my $p = $check->(@_);
$self->require_id('move');
DEBUG(sprintf("Moving event '%s' to calendar '%s'", $self->{id}, $p->{destination}));
my $result = $self->api(
uri => 'move',
method => 'post',
params => { destination => $p->{destination} },
);
return $result;
}
sub event_id { shift->{id}; }
sub calendar { shift->{calendar}; }
1;
__END__
=head1 NAME
Google::RestApi::CalendarApi3::Event - Event object for Google Calendar.
=head1 SYNOPSIS
# Create an event
my $event = $calendar->event()->create(
summary => 'Team Meeting',
start => { dateTime => '2026-03-01T10:00:00Z' },
end => { dateTime => '2026-03-01T11:00:00Z' },
);
# Quick add using natural language
my $event = $calendar->event()->quick_add(text => 'Lunch tomorrow at noon');
# Get event details
my $details = $event->get();
# Update event
$event->update(summary => 'Updated Meeting');
# Move event to another calendar
$event->move(destination => 'other_calendar_id');
# Delete event
$event->delete();
=head1 DESCRIPTION
Represents an event on a Google Calendar. Supports creating, reading,
updating, deleting, and moving events.
=head1 METHODS
lib/Google/RestApi/CalendarApi3/Event.pm view on Meta::CPAN
=head2 quick_add(text => $text)
Creates an event using natural language text parsing.
=head2 instances(params => \%params, max_pages => $n, page_callback => $coderef)
Lists instances of a recurring event. Requires event ID. C<max_pages> limits
the number of pages fetched (default 0 = unlimited). Supports C<page_callback>,
see L<Google::RestApi/PAGE CALLBACKS>.
=head2 move(destination => $calendar_id)
Moves the event to another calendar. Requires event ID.
=head2 event_id()
Returns the event ID.
=head2 calendar()
Returns the parent Calendar object.
=head1 AUTHORS
=over
=item
Robin Murray mvsjes@cpan.org
lib/Google/RestApi/CalendarApi3/Settings.pm view on Meta::CPAN
use Google::RestApi::Setup;
use parent 'Google::RestApi::SubResource';
sub new {
my $class = shift;
state $check = signature(
bless => !!0,
named => [
calendar_api => HasApi,
id => Str, { optional => 1 },
],
);
return bless $check->(@_), $class;
}
sub _uri_base { 'users/me/settings' }
sub _parent_accessor { 'calendar_api' }
sub get {
my $self = shift;
$self->require_id('get');
return $self->api();
}
sub value {
my $self = shift;
return $self->get()->{value};
}
sub setting_id { shift->{id}; }
sub calendar_api { shift->{calendar_api}; }
1;
__END__
=head1 NAME
Google::RestApi::CalendarApi3::Settings - Settings object for Google Calendar.
=head1 SYNOPSIS
# Get a specific setting
my $setting = $cal_api->settings(id => 'timezone');
my $details = $setting->get();
# Get just the value
my $tz = $setting->value();
=head1 DESCRIPTION
Provides access to user calendar settings (read-only).
=head1 METHODS
=head2 get()
Gets the setting details. Requires setting ID.
=head2 value()
Returns just the setting value. Requires setting ID.
=head2 setting_id()
Returns the setting ID.
=head2 calendar_api()
Returns the parent CalendarApi3 object.
=head1 AUTHORS
=over
=item
Robin Murray mvsjes@cpan.org
lib/Google/RestApi/SubResource.pm view on Meta::CPAN
duplicated C<api()> methods by providing a generic URI builder that
assembles C<_uri_base() + /$id + /$child_uri> and delegates to the
parent object's C<api()>.
Subclasses must override two methods:
=over
=item * C<_uri_base()> - returns the URI path segment (e.g. C<'comments'>, C<'events'>)
=item * C<_parent_accessor()> - returns the accessor name for the parent object (e.g. C<'file'>, C<'calendar'>)
=back
See L<Google::RestApi/Chained API Calls> for a walkthrough of how the
chained C<api()> delegation works.
=head1 METHODS
=head2 api(%args)
t/lib/Test/Unit/Utils.pm view on Meta::CPAN
use FindBin;
use File::Spec::Functions qw( catfile );
use Module::Load qw( load );
use Exporter qw(import);
our @EXPORT_OK = qw(
mock_config_file mock_token_file
mock_spreadsheet_name mock_spreadsheet_name2
mock_worksheet_id mock_worksheet_name
mock_rest_api mock_sheets_api mock_drive_api mock_calendar_api mock_gmail_api mock_tasks_api mock_docs_api
mock_calendar_id mock_task_list_id mock_document_id
drive_endpoint sheets_endpoint calendar_endpoint gmail_endpoint tasks_endpoint docs_endpoint
);
our %EXPORT_TAGS = (all => [ @EXPORT_OK ]);
sub mock_config_file { $ENV{GOOGLE_RESTAPI_CONFIG} ? $ENV{GOOGLE_RESTAPI_CONFIG} : catfile($FindBin::RealBin, qw(etc rest_config.yaml)); }
sub mock_token_file { catfile($FindBin::RealBin, qw(etc rest_config.token)); }
sub mock_spreadsheet_name { 'mock_spreadsheet1'; }
sub mock_spreadsheet_name2 { 'mock_spreadsheet2'; }
sub mock_worksheet_id { 0; }
sub mock_worksheet_name { 'Sheet1'; }
# require these ones so that errors in them don't prevent other tests from running.
sub mock_rest_api { _load_and_new('Google::RestApi', config_file => mock_config_file(), @_); }
sub mock_sheets_api { _load_and_new('Google::RestApi::SheetsApi4', api => mock_rest_api(), @_); }
sub mock_drive_api { _load_and_new('Google::RestApi::DriveApi3', api => mock_rest_api(), @_); }
sub mock_calendar_api { _load_and_new('Google::RestApi::CalendarApi3', api => mock_rest_api(), @_); }
sub mock_gmail_api { _load_and_new('Google::RestApi::GmailApi1', api => mock_rest_api(), @_); }
sub mock_tasks_api { _load_and_new('Google::RestApi::TasksApi1', api => mock_rest_api(), @_); }
sub mock_docs_api { _load_and_new('Google::RestApi::DocsApi1', api => mock_rest_api(), @_); }
sub mock_calendar_id { 'mock_calendar_id@group.calendar.google.com'; }
sub mock_task_list_id { 'mock_task_list_id_12345'; }
sub mock_document_id { 'mock_document_id_12345'; }
sub drive_endpoint { $Google::RestApi::DriveApi3::Drive_Endpoint; }
sub sheets_endpoint { $Google::RestApi::SheetsApi4::Sheets_Endpoint; }
sub calendar_endpoint { $Google::RestApi::CalendarApi3::Calendar_Endpoint; }
sub gmail_endpoint { $Google::RestApi::GmailApi1::Gmail_Endpoint; }
sub tasks_endpoint { $Google::RestApi::TasksApi1::Tasks_Endpoint; }
sub docs_endpoint { $Google::RestApi::DocsApi1::Docs_Endpoint; }
sub _load_and_new {
my $class = shift;
load $class;
return $class->new(@_);
}
t/unit/Test/Google/RestApi/CalendarApi3.pm view on Meta::CPAN
sub _constructor : Tests(4) {
my $self = shift;
throws_ok sub { CalendarApi3->new() },
qr/api/i,
'Constructor without api should throw';
ok my $cal = CalendarApi3->new(api => mock_rest_api()), 'Constructor should succeed';
isa_ok $cal, CalendarApi3, 'Constructor returns';
can_ok $cal, qw(api calendar calendar_list colors settings
create_calendar list_calendars freebusy);
return;
}
sub calendar_factory : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
ok my $cal = $cal_api->calendar(id => 'primary'), 'Calendar factory should succeed';
isa_ok $cal, Calendar, 'Calendar factory returns';
is $cal->calendar_id(), 'primary', 'Calendar has correct ID';
return;
}
sub calendar_list_factory : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
ok my $cl = $cal_api->calendar_list(id => 'primary'), 'CalendarList factory should succeed';
isa_ok $cl, CalendarList, 'CalendarList factory returns';
return;
}
sub colors_factory : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
ok my $colors = $cal_api->colors(), 'Colors factory should succeed';
isa_ok $colors, Colors, 'Colors factory returns';
return;
}
sub settings_factory : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
ok my $settings = $cal_api->settings(id => 'timezone'), 'Settings factory should succeed';
isa_ok $settings, Settings, 'Settings factory returns';
return;
}
sub create_and_delete_calendar : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $calendar = $cal_api->create_calendar(summary => 'Test Calendar');
isa_ok $calendar, Calendar, 'Create returns Calendar object';
ok my $cal_id = $calendar->calendar_id(), 'Calendar has ID';
lives_ok sub { $calendar->delete() }, 'Delete calendar lives';
return;
}
sub list_calendars : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
my @calendars = $cal_api->list_calendars();
ok scalar(@calendars) >= 1, 'List should return at least one calendar';
ok $calendars[0]->{id}, 'Calendar has an ID';
return;
}
sub list_calendars_max_pages : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
my @calendars = $cal_api->list_calendars(max_pages => 1);
ok scalar(@calendars) >= 1, 'List with max_pages should return results';
ok $calendars[0]->{id}, 'Calendar has an ID';
return;
}
1;
t/unit/Test/Google/RestApi/CalendarApi3.pm.exchanges view on Meta::CPAN
---
request: POST /calendar/v3/calendars
request_content:
summary: Test Calendar
response:
code: 200
content: |
{
"kind": "calendar#calendar",
"etag": "\"PcjBGQ84MbQ2n3GhVZHozUr8WjM\"",
"id": "5aadde077a778ab6ccccc3a30e90f51164c5cd4c13ecbdad6e9ead63e2c3b853@group.calendar.google.com",
"summary": "Test Calendar",
"timeZone": "UTC",
"dataOwner": "mvsjes2.test.restapi@gmail.com",
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"hangoutsMeet"
]
}
}
headers:
t/unit/Test/Google/RestApi/CalendarApi3.pm.exchanges view on Meta::CPAN
- chunked
- x-l2-request-path
- l2-managed-14
- vary
- X-Origin
- vary
- Referer
- vary
- Origin,Accept-Encoding
message: OK
source: Test::Google::RestApi::CalendarApi3::create_and_delete_calendar
---
request: DELETE /calendar/v3/calendars/5aadde077a778ab6ccccc3a30e90f51164c5cd4c13ecbdad6e9ead63e2c3b853@group.calendar.google.com
response:
code: 204
content: ''
headers:
- content-length
- '0'
- date
- Thu, 16 Apr 2026 19:11:43 GMT
- alt-svc
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
t/unit/Test/Google/RestApi/CalendarApi3.pm.exchanges view on Meta::CPAN
- Mon, 01 Jan 1990 00:00:00 GMT
- vary
- Origin
- vary
- X-Origin
- vary
- Referer
- x-l2-request-path
- l2-managed-14
message: No Content
source: Test::Google::RestApi::CalendarApi3::create_and_delete_calendar
---
query_params:
fields: nextPageToken, items(id, summary)
request: GET /calendar/v3/users/me/calendarList
response:
code: 200
content: |
{
"items": [
{
"id": "mvsjes2.test.restapi@gmail.com",
"summary": "mvsjes2.test.restapi@gmail.com"
},
{
"id": "5aadde077a778ab6ccccc3a30e90f51164c5cd4c13ecbdad6e9ead63e2c3b853@group.calendar.google.com",
"summary": "Test Calendar"
}
]
}
headers:
- vary
- X-Origin
- vary
- Referer
- vary
t/unit/Test/Google/RestApi/CalendarApi3.pm.exchanges view on Meta::CPAN
- chunked
- accept-ranges
- none
- x-frame-options
- SAMEORIGIN
- expires
- Thu, 16 Apr 2026 19:11:44 GMT
- date
- Thu, 16 Apr 2026 19:11:44 GMT
message: OK
source: Test::Google::RestApi::CalendarApi3::list_calendars
---
query_params:
fields: nextPageToken, items(id, summary)
request: GET /calendar/v3/users/me/calendarList
response:
code: 200
content: |
{
"items": [
{
"id": "mvsjes2.test.restapi@gmail.com",
"summary": "mvsjes2.test.restapi@gmail.com"
},
{
"id": "5aadde077a778ab6ccccc3a30e90f51164c5cd4c13ecbdad6e9ead63e2c3b853@group.calendar.google.com",
"summary": "Test Calendar"
}
]
}
headers:
- cache-control
- private, max-age=0, must-revalidate, no-transform
- content-type
- application/json; charset=UTF-8
- transfer-encoding
t/unit/Test/Google/RestApi/CalendarApi3.pm.exchanges view on Meta::CPAN
- Thu, 16 Apr 2026 19:11:46 GMT
- x-content-type-options
- nosniff
- alt-svc
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
- x-xss-protection
- '0'
- server
- ESF
message: OK
source: Test::Google::RestApi::CalendarApi3::list_calendars_max_pages
t/unit/Test/Google/RestApi/CalendarApi3/Acl.pm view on Meta::CPAN
use Google::RestApi::Types qw( :all );
use aliased 'Google::RestApi::CalendarApi3::Acl';
use parent 'Test::Unit::TestBase';
init_logger;
sub dont_create_mock_spreadsheets { 1; }
sub _setup_live_calendar : Tests(startup) {
my $self = shift;
return unless $ENV{GOOGLE_RESTAPI_CONFIG};
my $cal_api = mock_calendar_api();
my $cal = $cal_api->create_calendar(summary => 'Test Calendar ACL');
$self->{_live_cal} = $cal;
return;
}
sub _teardown_live_calendar : Tests(shutdown) {
my $self = shift;
$self->{_live_cal}->delete() if $self->{_live_cal};
return;
}
sub _cal_id {
my $self = shift;
return $self->{_live_cal} ? $self->{_live_cal}->calendar_id() : mock_calendar_id();
}
sub _constructor : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
ok my $acl = Acl->new(calendar => $cal),
'Constructor without id should succeed';
isa_ok $acl, Acl, 'Constructor returns';
ok Acl->new(calendar => $cal, id => 'user:test@example.com'),
'Constructor with id should succeed';
return;
}
sub requires_id : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
my $acl = Acl->new(calendar => $cal);
throws_ok sub { $acl->get() },
qr/ACL ID required/i,
'get() without ID should throw';
throws_ok sub { $acl->update(role => 'writer') },
qr/ACL ID required/i,
'update() without ID should throw';
throws_ok sub { $acl->delete() },
qr/ACL ID required/i,
'delete() without ID should throw';
return;
}
sub create_and_delete : Tests(4) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
my $acl = $cal->acl()->create(
role => 'reader',
scope_type => 'user',
scope_value => 'test@example.com',
);
isa_ok $acl, Acl, 'Create returns Acl object';
ok my $acl_id = $acl->acl_id(), 'ACL has ID';
my $details = $acl->get();
t/unit/Test/Google/RestApi/CalendarApi3/Acl.pm.exchanges view on Meta::CPAN
---
request: POST /calendar/v3/calendars/26f0675c4cdad5cce673ee3b1ecf465639646971313b52db3e9d84fd260c9b75@group.calendar.google.com/acl
request_content:
role: reader
scope:
type: user
value: test@example.com
response:
code: 200
content: |
{
"kind": "calendar#aclRule",
"etag": "\"00001776366886140159\"",
"id": "user:test@example.com",
"scope": {
"type": "user",
"value": "test@example.com"
},
"role": "reader"
}
headers:
- date
t/unit/Test/Google/RestApi/CalendarApi3/Acl.pm.exchanges view on Meta::CPAN
- vary
- Referer
- vary
- Origin,Accept-Encoding
- x-l2-request-path
- l2-managed-14
message: OK
source: Test::Google::RestApi::CalendarApi3::Acl::create_and_delete
---
request: GET /calendar/v3/calendars/26f0675c4cdad5cce673ee3b1ecf465639646971313b52db3e9d84fd260c9b75@group.calendar.google.com/acl/user:test@example.com
response:
code: 200
content: |
{
"kind": "calendar#aclRule",
"etag": "\"00001776366886140159\"",
"id": "user:test@example.com",
"scope": {
"type": "user",
"value": "test@example.com"
},
"role": "reader"
}
headers:
- content-type
t/unit/Test/Google/RestApi/CalendarApi3/Acl.pm.exchanges view on Meta::CPAN
- x-content-type-options
- nosniff
- x-l2-request-path
- l2-managed-14
- server
- ESF
message: OK
source: Test::Google::RestApi::CalendarApi3::Acl::create_and_delete
---
request: DELETE /calendar/v3/calendars/26f0675c4cdad5cce673ee3b1ecf465639646971313b52db3e9d84fd260c9b75@group.calendar.google.com/acl/user:test@example.com
response:
code: 204
content: ''
headers:
- x-frame-options
- SAMEORIGIN
- date
- Thu, 16 Apr 2026 19:14:50 GMT
- expires
- Mon, 01 Jan 1990 00:00:00 GMT
t/unit/Test/Google/RestApi/CalendarApi3/Acl.pm.exchanges view on Meta::CPAN
- x-content-type-options
- nosniff
- x-xss-protection
- '0'
- alt-svc
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
message: No Content
source: Test::Google::RestApi::CalendarApi3::Acl::create_and_delete
---
request: DELETE /calendar/v3/calendars/26f0675c4cdad5cce673ee3b1ecf465639646971313b52db3e9d84fd260c9b75@group.calendar.google.com
response:
code: 204
content: ''
headers:
- date
- Thu, 16 Apr 2026 19:14:51 GMT
- content-length
- '0'
- pragma
- no-cache
t/unit/Test/Google/RestApi/CalendarApi3/Acl.pm.exchanges view on Meta::CPAN
- no-cache, no-store, max-age=0, must-revalidate
- x-l2-request-path
- l2-managed-14
- vary
- Origin
- vary
- X-Origin
- vary
- Referer
message: No Content
source: Test::Google::RestApi::CalendarApi3::Acl::_teardown_live_calendar
t/unit/Test/Google/RestApi/CalendarApi3/Calendar.pm view on Meta::CPAN
use aliased 'Google::RestApi::CalendarApi3::Calendar';
use aliased 'Google::RestApi::CalendarApi3::Event';
use aliased 'Google::RestApi::CalendarApi3::Acl';
use parent 'Test::Unit::TestBase';
init_logger;
sub dont_create_mock_spreadsheets { 1; }
sub _setup_live_calendar : Tests(startup) {
my $self = shift;
return unless $ENV{GOOGLE_RESTAPI_CONFIG};
my $cal_api = mock_calendar_api();
my $cal = $cal_api->create_calendar(summary => 'Test Calendar');
$self->{_live_cal} = $cal;
return;
}
sub _teardown_live_calendar : Tests(shutdown) {
my $self = shift;
$self->{_live_cal}->delete() if $self->{_live_cal};
return;
}
sub _cal_id {
my $self = shift;
return $self->{_live_cal} ? $self->{_live_cal}->calendar_id() : mock_calendar_id();
}
sub _constructor : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
ok my $cal = Calendar->new(calendar_api => $cal_api, id => 'primary'),
'Constructor should succeed';
isa_ok $cal, Calendar, 'Constructor returns';
is $cal->calendar_id(), 'primary', 'Calendar has correct ID';
return;
}
sub get : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
my $metadata = $cal->get();
ok $metadata, 'Get returns metadata';
ok $metadata->{summary}, 'Metadata has summary';
return;
}
sub update : Tests(1) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
lives_ok sub { $cal->update(summary => 'Updated Calendar') }, 'Update lives';
return;
}
sub event_factory : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
ok my $event = $cal->event(), 'Event factory without ID should succeed';
isa_ok $event, Event, 'Event factory returns';
return;
}
sub events_max_pages : Tests(1) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
my @events = $cal->events(max_pages => 1);
ok defined(\@events), 'Events with max_pages returns array';
return;
}
sub acl_rules_max_pages : Tests(1) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
my @rules = $cal->acl_rules(max_pages => 1);
ok defined(\@rules), 'acl_rules with max_pages accepts param';
return;
}
sub acl_factory : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
ok my $acl = $cal->acl(), 'ACL factory without ID should succeed';
isa_ok $acl, Acl, 'ACL factory returns';
return;
}
1;
t/unit/Test/Google/RestApi/CalendarApi3/Calendar.pm.exchanges view on Meta::CPAN
---
query_params:
fields: nextPageToken, items(id, role, scope)
request: GET /calendar/v3/calendars/bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com/acl
response:
code: 200
content: |
{
"items": [
{
"id": "user:bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com",
"scope": {
"type": "user",
"value": "bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com"
},
"role": "owner"
},
{
"id": "user:mvsjes2.test.restapi@gmail.com",
"scope": {
"type": "user",
"value": "mvsjes2.test.restapi@gmail.com"
},
"role": "owner"
t/unit/Test/Google/RestApi/CalendarApi3/Calendar.pm.exchanges view on Meta::CPAN
- server
- ESF
- date
- Thu, 16 Apr 2026 19:17:15 GMT
message: OK
source: Test::Google::RestApi::CalendarApi3::Calendar::acl_rules_max_pages
---
query_params:
fields: nextPageToken, items(id, summary, start, end)
request: GET /calendar/v3/calendars/bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com/events
response:
code: 200
content: "{\n \"items\": []\n}\n"
headers:
- date
- Thu, 16 Apr 2026 19:17:17 GMT
- server
- ESF
- alt-svc
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
t/unit/Test/Google/RestApi/CalendarApi3/Calendar.pm.exchanges view on Meta::CPAN
- vary
- X-Origin
- vary
- Referer
- vary
- Origin,Accept-Encoding
message: OK
source: Test::Google::RestApi::CalendarApi3::Calendar::events_max_pages
---
request: GET /calendar/v3/calendars/bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com
response:
code: 200
content: |
{
"kind": "calendar#calendar",
"etag": "\"hCU6DklFL59A_vm97O_CgKmxiF4\"",
"id": "bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com",
"summary": "Test Calendar",
"timeZone": "UTC",
"dataOwner": "mvsjes2.test.restapi@gmail.com",
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"hangoutsMeet"
]
}
}
headers:
t/unit/Test/Google/RestApi/CalendarApi3/Calendar.pm.exchanges view on Meta::CPAN
- x-frame-options
- SAMEORIGIN
- expires
- Thu, 16 Apr 2026 19:17:18 GMT
- accept-ranges
- none
message: OK
source: Test::Google::RestApi::CalendarApi3::Calendar::get
---
request: PUT /calendar/v3/calendars/bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com
request_content:
summary: Updated Calendar
response:
code: 200
content: |
{
"kind": "calendar#calendar",
"etag": "\"N6osDLBhMWn_LRZiYrT95Mr9unw\"",
"id": "bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com",
"summary": "Updated Calendar",
"timeZone": "UTC",
"dataOwner": "mvsjes2.test.restapi@gmail.com",
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"hangoutsMeet"
]
}
}
headers:
t/unit/Test/Google/RestApi/CalendarApi3/Calendar.pm.exchanges view on Meta::CPAN
- x-xss-protection
- '0'
- alt-svc
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
- date
- Thu, 16 Apr 2026 19:17:20 GMT
message: OK
source: Test::Google::RestApi::CalendarApi3::Calendar::update
---
request: DELETE /calendar/v3/calendars/bc70ef6c1ca0ca2702782cbd0ee2178a77ae484beca1d2924ba2eb251a1e25ad@group.calendar.google.com
response:
code: 204
content: ''
headers:
- vary
- Origin
- vary
- X-Origin
- vary
- Referer
t/unit/Test/Google/RestApi/CalendarApi3/Calendar.pm.exchanges view on Meta::CPAN
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
- server
- ESF
- pragma
- no-cache
- content-length
- '0'
- date
- Thu, 16 Apr 2026 19:17:22 GMT
message: No Content
source: Test::Google::RestApi::CalendarApi3::Calendar::_teardown_live_calendar
t/unit/Test/Google/RestApi/CalendarApi3/CalendarList.pm view on Meta::CPAN
use parent 'Test::Unit::TestBase';
init_logger;
sub dont_create_mock_spreadsheets { 1; }
sub _constructor : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
ok my $cl = CalendarList->new(calendar_api => $cal_api),
'Constructor without id should succeed';
isa_ok $cl, CalendarList, 'Constructor returns';
ok CalendarList->new(calendar_api => $cal_api, id => 'primary'),
'Constructor with id should succeed';
return;
}
sub get : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cl = $cal_api->calendar_list(id => 'primary');
my $details = $cl->get();
ok $details, 'Get returns details';
ok $details->{summary}, 'Details has summary';
return;
}
1;
t/unit/Test/Google/RestApi/CalendarApi3/CalendarList.pm.exchanges view on Meta::CPAN
---
request: GET /calendar/v3/users/me/calendarList/primary
response:
code: 200
content: |
{
"kind": "calendar#calendarListEntry",
"etag": "\"1776114053940570\"",
"id": "mvsjes2.test.restapi@gmail.com",
"summary": "mvsjes2.test.restapi@gmail.com",
"timeZone": "UTC",
"colorId": "14",
"backgroundColor": "#9fe1e7",
"foregroundColor": "#000000",
"selected": true,
"accessRole": "owner",
"defaultReminders": [
t/unit/Test/Google/RestApi/CalendarApi3/Colors.pm view on Meta::CPAN
use parent 'Test::Unit::TestBase';
init_logger;
sub dont_create_mock_spreadsheets { 1; }
sub _constructor : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
ok my $colors = Colors->new(calendar_api => $cal_api),
'Constructor should succeed';
isa_ok $colors, Colors, 'Constructor returns';
return;
}
sub get : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $colors = $cal_api->colors();
my $result = $colors->get();
ok $result, 'Get returns result';
ok $result->{calendar}, 'Result has calendar colors';
ok $result->{event}, 'Result has event colors';
return;
}
1;
t/unit/Test/Google/RestApi/CalendarApi3/Colors.pm.exchanges view on Meta::CPAN
---
request: GET /calendar/v3/colors
response:
code: 200
content: |
{
"kind": "calendar#colors",
"updated": "2012-02-14T00:00:00.000Z",
"calendar": {
"1": {
"background": "#ac725e",
"foreground": "#1d1d1d"
},
"2": {
"background": "#d06b64",
"foreground": "#1d1d1d"
},
"3": {
"background": "#f83a22",
t/unit/Test/Google/RestApi/CalendarApi3/Event.pm view on Meta::CPAN
use Google::RestApi::Types qw( :all );
use aliased 'Google::RestApi::CalendarApi3::Event';
use parent 'Test::Unit::TestBase';
init_logger;
sub dont_create_mock_spreadsheets { 1; }
sub _setup_live_calendar : Tests(startup) {
my $self = shift;
return unless $ENV{GOOGLE_RESTAPI_CONFIG};
my $cal_api = mock_calendar_api();
my $cal = $cal_api->create_calendar(summary => 'Test Calendar Events');
$self->{_live_cal} = $cal;
return;
}
sub _teardown_live_calendar : Tests(shutdown) {
my $self = shift;
$self->{_live_cal}->delete() if $self->{_live_cal};
return;
}
sub _cal_id {
my $self = shift;
return $self->{_live_cal} ? $self->{_live_cal}->calendar_id() : mock_calendar_id();
}
sub _constructor : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
ok my $event = Event->new(calendar => $cal),
'Constructor without id should succeed';
isa_ok $event, Event, 'Constructor returns';
ok Event->new(calendar => $cal, id => 'event123'),
'Constructor with id should succeed';
return;
}
sub requires_id : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
my $event = Event->new(calendar => $cal);
throws_ok sub { $event->get() },
qr/Event ID required/i,
'get() without ID should throw';
throws_ok sub { $event->update(summary => 'test') },
qr/Event ID required/i,
'update() without ID should throw';
throws_ok sub { $event->delete() },
qr/Event ID required/i,
'delete() without ID should throw';
return;
}
sub create_and_delete : Tests(4) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
my $event = $cal->event()->create(
summary => 'Test Event',
start => { dateTime => '2026-03-01T10:00:00Z' },
end => { dateTime => '2026-03-01T11:00:00Z' },
);
isa_ok $event, Event, 'Create returns Event object';
ok my $event_id = $event->event_id(), 'Event has ID';
my $details = $event->get();
ok $details, 'Get returns event details';
lives_ok sub { $event->delete() }, 'Delete event lives';
return;
}
sub quick_add : Tests(3) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $cal = $cal_api->calendar(id => $self->_cal_id());
my $event = $cal->event()->quick_add(text => 'Lunch tomorrow at noon');
isa_ok $event, Event, 'Quick add returns Event object';
ok $event->event_id(), 'Quick add event has ID';
lives_ok sub { $event->delete() }, 'Delete quick add event lives';
return;
}
t/unit/Test/Google/RestApi/CalendarApi3/Event.pm.exchanges view on Meta::CPAN
---
request: POST /calendar/v3/calendars/0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com/events
request_content:
end:
dateTime: 2026-03-01T11:00:00Z
start:
dateTime: 2026-03-01T10:00:00Z
summary: Test Event
response:
code: 200
content: |
{
"kind": "calendar#event",
"etag": "\"3552733669210686\"",
"id": "3sjmu3nh7n1bt9qv5aodl0agd4",
"status": "confirmed",
"htmlLink": "https://www.google.com/calendar/event?eid=M3NqbXUzbmg3bjFidDlxdjVhb2RsMGFnZDQgMDkzOGRhNjRjZGE4NTlkNzIxODFjYjJmOGUwNDg5YzIyZjE5ZjNkMzg4YTZkNWZjNTc5YmRjZTI5YWFlNzBkZUBn",
"created": "2026-04-16T19:13:54.000Z",
"updated": "2026-04-16T19:13:54.605Z",
"summary": "Test Event",
"creator": {
"email": "mvsjes2.test.restapi@gmail.com"
},
"organizer": {
"email": "0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com",
"displayName": "Test Calendar Events",
"self": true
},
"start": {
"dateTime": "2026-03-01T10:00:00Z",
"timeZone": "UTC"
},
"end": {
"dateTime": "2026-03-01T11:00:00Z",
"timeZone": "UTC"
t/unit/Test/Google/RestApi/CalendarApi3/Event.pm.exchanges view on Meta::CPAN
- vary
- Referer
- vary
- Origin,Accept-Encoding
- x-l2-request-path
- l2-managed-14
message: OK
source: Test::Google::RestApi::CalendarApi3::Event::create_and_delete
---
request: GET /calendar/v3/calendars/0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com/events/3sjmu3nh7n1bt9qv5aodl0agd4
response:
code: 200
content: |
{
"kind": "calendar#event",
"etag": "\"3552733669210686\"",
"id": "3sjmu3nh7n1bt9qv5aodl0agd4",
"status": "confirmed",
"htmlLink": "https://www.google.com/calendar/event?eid=M3NqbXUzbmg3bjFidDlxdjVhb2RsMGFnZDQgMDkzOGRhNjRjZGE4NTlkNzIxODFjYjJmOGUwNDg5YzIyZjE5ZjNkMzg4YTZkNWZjNTc5YmRjZTI5YWFlNzBkZUBn",
"created": "2026-04-16T19:13:54.000Z",
"updated": "2026-04-16T19:13:54.605Z",
"summary": "Test Event",
"creator": {
"email": "mvsjes2.test.restapi@gmail.com"
},
"organizer": {
"email": "0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com",
"displayName": "Test Calendar Events",
"self": true
},
"start": {
"dateTime": "2026-03-01T10:00:00Z",
"timeZone": "UTC"
},
"end": {
"dateTime": "2026-03-01T11:00:00Z",
"timeZone": "UTC"
t/unit/Test/Google/RestApi/CalendarApi3/Event.pm.exchanges view on Meta::CPAN
- x-xss-protection
- '0'
- x-content-type-options
- nosniff
- server
- ESF
message: OK
source: Test::Google::RestApi::CalendarApi3::Event::create_and_delete
---
request: DELETE /calendar/v3/calendars/0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com/events/3sjmu3nh7n1bt9qv5aodl0agd4
response:
code: 204
content: ''
headers:
- server
- ESF
- pragma
- no-cache
- x-content-type-options
- nosniff
t/unit/Test/Google/RestApi/CalendarApi3/Event.pm.exchanges view on Meta::CPAN
- cache-control
- no-cache, no-store, max-age=0, must-revalidate
- content-type
- text/html
message: No Content
source: Test::Google::RestApi::CalendarApi3::Event::create_and_delete
---
query_params:
text: Lunch tomorrow at noon
request: POST /calendar/v3/calendars/0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com/events/quickAdd
response:
code: 200
content: |
{
"kind": "calendar#event",
"etag": "\"3552733678281022\"",
"id": "ui7l51hgjcb5auqv3nmv36u4eg",
"status": "confirmed",
"htmlLink": "https://www.google.com/calendar/event?eid=dWk3bDUxaGdqY2I1YXVxdjNubXYzNnU0ZWcgMDkzOGRhNjRjZGE4NTlkNzIxODFjYjJmOGUwNDg5YzIyZjE5ZjNkMzg4YTZkNWZjNTc5YmRjZTI5YWFlNzBkZUBn",
"created": "2026-04-16T19:13:59.000Z",
"updated": "2026-04-16T19:13:59.140Z",
"summary": "Lunch",
"creator": {
"email": "mvsjes2.test.restapi@gmail.com"
},
"organizer": {
"email": "0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com",
"displayName": "Test Calendar Events",
"self": true
},
"start": {
"dateTime": "2026-04-17T12:00:00Z",
"timeZone": "UTC"
},
"end": {
"dateTime": "2026-04-17T13:00:00Z",
"timeZone": "UTC"
t/unit/Test/Google/RestApi/CalendarApi3/Event.pm.exchanges view on Meta::CPAN
- vary
- X-Origin
- vary
- Referer
- vary
- Origin,Accept-Encoding
message: OK
source: Test::Google::RestApi::CalendarApi3::Event::quick_add
---
request: DELETE /calendar/v3/calendars/0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com/events/ui7l51hgjcb5auqv3nmv36u4eg
response:
code: 204
content: ''
headers:
- x-content-type-options
- nosniff
- x-xss-protection
- '0'
- alt-svc
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
t/unit/Test/Google/RestApi/CalendarApi3/Event.pm.exchanges view on Meta::CPAN
- content-type
- text/html
- x-frame-options
- SAMEORIGIN
- expires
- Mon, 01 Jan 1990 00:00:00 GMT
message: No Content
source: Test::Google::RestApi::CalendarApi3::Event::quick_add
---
request: DELETE /calendar/v3/calendars/0938da64cda859d72181cb2f8e0489c22f19f3d388a6d5fc579bdce29aae70de@group.calendar.google.com
response:
code: 204
content: ''
headers:
- expires
- Mon, 01 Jan 1990 00:00:00 GMT
- x-frame-options
- SAMEORIGIN
- content-type
- text/html
t/unit/Test/Google/RestApi/CalendarApi3/Event.pm.exchanges view on Meta::CPAN
- no-cache
- server
- ESF
- x-xss-protection
- '0'
- alt-svc
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
- x-content-type-options
- nosniff
message: No Content
source: Test::Google::RestApi::CalendarApi3::Event::_teardown_live_calendar
t/unit/Test/Google/RestApi/CalendarApi3/Settings.pm view on Meta::CPAN
use parent 'Test::Unit::TestBase';
init_logger;
sub dont_create_mock_spreadsheets { 1; }
sub _constructor : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
ok my $settings = Settings->new(calendar_api => $cal_api, id => 'timezone'),
'Constructor should succeed';
isa_ok $settings, Settings, 'Constructor returns';
return;
}
sub get : Tests(2) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $settings = $cal_api->settings(id => 'timezone');
my $result = $settings->get();
ok $result, 'Get returns result';
ok $result->{value}, 'Result has value';
return;
}
sub value : Tests(1) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $settings = $cal_api->settings(id => 'timezone');
my $value = $settings->value();
ok $value, 'Value returns a timezone string';
return;
}
sub requires_id : Tests(1) {
my $self = shift;
my $cal_api = mock_calendar_api();
my $settings = Settings->new(calendar_api => $cal_api);
throws_ok sub { $settings->get() },
qr/Settings ID required/i,
'get() without ID should throw';
return;
}
1;
t/unit/Test/Google/RestApi/CalendarApi3/Settings.pm.exchanges view on Meta::CPAN
---
request: GET /calendar/v3/users/me/settings/timezone
response:
code: 200
content: |
{
"kind": "calendar#setting",
"etag": "\"1776114053940570\"",
"id": "timezone",
"value": "UTC"
}
headers:
- alt-svc
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
- x-xss-protection
- '0'
- x-content-type-options
t/unit/Test/Google/RestApi/CalendarApi3/Settings.pm.exchanges view on Meta::CPAN
- x-frame-options
- SAMEORIGIN
- expires
- Thu, 16 Apr 2026 19:07:42 GMT
- accept-ranges
- none
message: OK
source: Test::Google::RestApi::CalendarApi3::Settings::get
---
request: GET /calendar/v3/users/me/settings/timezone
response:
code: 200
content: |
{
"kind": "calendar#setting",
"etag": "\"1776114053940570\"",
"id": "timezone",
"value": "UTC"
}
headers:
- x-content-type-options
- nosniff
- x-xss-protection
- '0'
- alt-svc
t/unit/Test/Google/RestApi/ScopeCheck.pm view on Meta::CPAN
scope => 'https://www.googleapis.com/auth/drive',
uri => 'https://www.googleapis.com/drive/v3/about?fields=user',
},
{
name => 'Sheets API',
scope => 'https://www.googleapis.com/auth/spreadsheets',
uri => 'https://sheets.googleapis.com/v4/spreadsheets/scope_check_probe',
},
{
name => 'Calendar API',
scope => 'https://www.googleapis.com/auth/calendar',
uri => 'https://www.googleapis.com/calendar/v3/users/me/calendarList?maxResults=1',
},
{
name => 'Docs API',
scope => 'https://www.googleapis.com/auth/documents',
uri => 'https://docs.googleapis.com/v1/documents/scope_check_probe',
},
{
name => 'Gmail API',
scope => 'https://www.googleapis.com/auth/gmail.modify',
uri => 'https://gmail.googleapis.com/gmail/v1/users/me/profile',
tutorial/99_delete_all.pl view on Meta::CPAN
init_logger($TRACE) if $ENV{DEBUG};
my $name = spreadsheet_name();
my $sheets_api = sheets_api();
$sheets_api->rest_api()->api_callback(\&show_api);
start("Now we will delete all the spreadsheets we created by listing all spreadsheets deleting any named $name.");
my $count = $sheets_api->delete_all_spreadsheets_by_filters(["name = '$name'", "name = '${name}_copy'", "name = '${name}_drive_copy'"]);
end("Delete complete, deleted $count spreadsheets.");
# clean up calendars.
my $cal_name = calendar_name();
start("Now we will delete all calendars named '$cal_name'.");
my $cal_api = calendar_api();
$cal_api->rest_api()->api_callback(\&show_api);
my @calendars = $cal_api->list_calendars();
my $cal_count = 0;
for my $cal (@calendars) {
if ($cal->{summary} && $cal->{summary} eq $cal_name) {
$cal_api->calendar(id => $cal->{id})->delete();
$cal_count++;
}
}
end_go("Calendar delete complete, deleted $cal_count calendar(s).");
# clean up gmail labels.
my $gmail_label = gmail_label_name();
start("Now we will delete any Gmail labels named '$gmail_label' or '${gmail_label}_updated'.");
my $gmail = gmail_api();
$gmail->rest_api()->api_callback(\&show_api);
my @gmail_labels = $gmail->labels();
my $gmail_count = 0;
for my $label (@gmail_labels) {
if ($label->{name} && ($label->{name} eq $gmail_label || $label->{name} eq "${gmail_label}_updated")
tutorial/calendar/10_calendar_basics.pl view on Meta::CPAN
#!/usr/bin/env perl
# This tutorial demonstrates Calendar API basic operations:
# - Listing calendars
# - Creating a new calendar
# - Getting/updating calendar metadata
# - Showing available colors
# - Deleting a calendar
#
# Run with: GOOGLE_RESTAPI_CONFIG=~/.google/rest_api.yaml perl tutorial/calendar/10_calendar_basics.pl
# Add DEBUG=1 for verbose API logging.
use FindBin;
use lib "$FindBin::RealBin/../lib";
use lib "$FindBin::RealBin/../../t/lib";
use lib "$FindBin::RealBin/../../lib";
use Tutorial::Setup;
init_logger($TRACE) if $ENV{DEBUG};
my $name = calendar_name();
my $cal_api = calendar_api();
# clean up any failed previous runs.
start("Cleaning up any calendars from previous tutorial runs.");
my @existing = $cal_api->list_calendars();
for my $cal (@existing) {
if ($cal->{summary} && $cal->{summary} eq $name) {
$cal_api->calendar(id => $cal->{id})->delete();
}
}
end("Cleanup complete.");
# now set a callback to display the api request/response.
$cal_api->rest_api()->api_callback(\&show_api);
# list the user's calendars.
start("Listing your calendars.");
my @calendars = $cal_api->list_calendars();
end("You have " . scalar(@calendars) . " calendar(s):\n" . Dump(\@calendars));
# create a new calendar.
start("Creating a new calendar named '$name'.");
my $calendar = $cal_api->create_calendar(summary => $name);
my $cal_id = $calendar->calendar_id();
end("Calendar created with ID: $cal_id.");
# get calendar metadata.
start("Getting the calendar's metadata.");
my $metadata = $calendar->get();
end("Calendar metadata:\n" . Dump($metadata));
# update calendar metadata.
start("Updating the calendar's description and location.");
$calendar->update(
summary => $name,
description => 'Created by Google::RestApi Calendar tutorial',
location => 'Sydney, Australia',
);
my $updated = $calendar->get();
end("Updated calendar:\n" . Dump($updated));
# show available colors.
start("Fetching available calendar and event colors.");
my $colors = $cal_api->colors();
my $all_colors = $colors->get();
end("Available colors:\n" . Dump($all_colors));
# delete the calendar.
start("Now we'll delete the calendar we created.");
$calendar->delete();
end("Calendar '$name' deleted.");
message('green', "\nCalendar basics tutorial complete!");
message('green', "Proceed to 20_events.pl to see event operations.\n");
message('blue', "We are done, here are some api stats:\n", Dump($cal_api->rest_api()->stats()));