Google-RestApi

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

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

README.md  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(

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()));



( run in 3.307 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )