Google Calendar: Domain-Wide Delegation support for attendee invitations
Service account can now impersonate a Workspace user (set gcal_impersonate_email in config) to unlock attendee invitations with push notifications. Falls back to silent event creation if impersonation is not configured. Setup required in Google Admin Console: Security → API Controls → Domain-wide delegation → Add service account client_id with scope: https://www.googleapis.com/auth/calendar Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,3 +3,4 @@ defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
$config['gcal_service_account_path'] = APPPATH . 'config/service-account-key.json';
|
||||
$config['gcal_evelin_calendar_id'] = 'katozoltan0804@gmail.com'; // Evelin's Calendar ID (e.g. her Gmail address)
|
||||
$config['gcal_impersonate_email'] = ''; // Workspace user to impersonate (e.g. evelin@studiobeve.no) — required for attendee invitations
|
||||
|
||||
@@ -451,11 +451,11 @@ class Pages extends CI_Controller {
|
||||
$workerEventId = null;
|
||||
$ownerEventId = null;
|
||||
if(!empty($worker->google_calendar_id)){
|
||||
$workerEventId = $this->googlecalendar->createEvent($worker->google_calendar_id, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd);
|
||||
$workerEventId = $this->googlecalendar->createEvent($worker->google_calendar_id, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd, $worker->google_calendar_id);
|
||||
}
|
||||
$evelinCalId = $this->config->item('gcal_evelin_calendar_id');
|
||||
if(!empty($evelinCalId)){
|
||||
$ownerEventId = $this->googlecalendar->createEvent($evelinCalId, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd);
|
||||
$ownerEventId = $this->googlecalendar->createEvent($evelinCalId, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd, $evelinCalId);
|
||||
}
|
||||
$this->Service_model->updateBookingCalEvents($newBooking->booking_id, $workerEventId, $ownerEventId);
|
||||
}
|
||||
@@ -873,10 +873,10 @@ class Pages extends CI_Controller {
|
||||
$newWorkerEventId = null;
|
||||
$newOwnerEventId = null;
|
||||
if(!empty($worker->google_calendar_id)){
|
||||
$newWorkerEventId = $this->googlecalendar->createEvent($worker->google_calendar_id, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd);
|
||||
$newWorkerEventId = $this->googlecalendar->createEvent($worker->google_calendar_id, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd, $worker->google_calendar_id);
|
||||
}
|
||||
if(!empty($evelinCalId)){
|
||||
$newOwnerEventId = $this->googlecalendar->createEvent($evelinCalId, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd);
|
||||
$newOwnerEventId = $this->googlecalendar->createEvent($evelinCalId, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd, $evelinCalId);
|
||||
}
|
||||
$this->Service_model->updateBookingCalEvents($booking->booking_id, $newWorkerEventId, $newOwnerEventId);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
class GoogleCalendar {
|
||||
|
||||
private $service = null;
|
||||
private $canInvite = false;
|
||||
|
||||
public function __construct() {
|
||||
require_once FCPATH . 'vendor/autoload.php';
|
||||
@@ -20,6 +21,14 @@ class GoogleCalendar {
|
||||
$client = new Google_Client();
|
||||
$client->setAuthConfig($serviceAccountPath);
|
||||
$client->setScopes([Google_Service_Calendar::CALENDAR]);
|
||||
|
||||
// Domain-Wide Delegation: impersonate a Workspace user to unlock attendee invitations
|
||||
$impersonateEmail = $CI->config->item('gcal_impersonate_email');
|
||||
if (!empty($impersonateEmail)) {
|
||||
$client->setSubject($impersonateEmail);
|
||||
$this->canInvite = true;
|
||||
}
|
||||
|
||||
$this->service = new Google_Service_Calendar($client);
|
||||
} catch (Exception $e) {
|
||||
// Silently fail — calendar errors must never break the booking flow
|
||||
@@ -28,18 +37,25 @@ class GoogleCalendar {
|
||||
|
||||
/**
|
||||
* Create a calendar event.
|
||||
* If Domain-Wide Delegation is configured and $attendeeEmail is provided,
|
||||
* the attendee receives an invitation push notification via Google Calendar.
|
||||
* @return string|null The new event ID, or null on failure.
|
||||
*/
|
||||
public function createEvent($calendarId, $title, $description, $startDatetime, $endDatetime) {
|
||||
public function createEvent($calendarId, $title, $description, $startDatetime, $endDatetime, $attendeeEmail = null) {
|
||||
if (!$this->service || empty($calendarId)) return null;
|
||||
try {
|
||||
$event = new Google_Service_Calendar_Event([
|
||||
$eventData = [
|
||||
'summary' => $title,
|
||||
'description' => $description,
|
||||
'start' => ['dateTime' => $startDatetime, 'timeZone' => 'Europe/Oslo'],
|
||||
'end' => ['dateTime' => $endDatetime, 'timeZone' => 'Europe/Oslo'],
|
||||
]);
|
||||
$result = $this->service->events->insert($calendarId, $event);
|
||||
];
|
||||
if ($this->canInvite && !empty($attendeeEmail)) {
|
||||
$eventData['attendees'] = [['email' => $attendeeEmail]];
|
||||
}
|
||||
$event = new Google_Service_Calendar_Event($eventData);
|
||||
$params = ($this->canInvite && !empty($attendeeEmail)) ? ['sendUpdates' => 'all'] : [];
|
||||
$result = $this->service->events->insert($calendarId, $event, $params);
|
||||
return $result->getId();
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
@@ -50,7 +66,7 @@ class GoogleCalendar {
|
||||
* Update an existing calendar event.
|
||||
* @return string|null The event ID, or null on failure.
|
||||
*/
|
||||
public function updateEvent($calendarId, $eventId, $title, $description, $startDatetime, $endDatetime) {
|
||||
public function updateEvent($calendarId, $eventId, $title, $description, $startDatetime, $endDatetime, $attendeeEmail = null) {
|
||||
if (!$this->service || empty($calendarId) || empty($eventId)) return null;
|
||||
try {
|
||||
$event = $this->service->events->get($calendarId, $eventId);
|
||||
@@ -64,7 +80,11 @@ class GoogleCalendar {
|
||||
'dateTime' => $endDatetime,
|
||||
'timeZone' => 'Europe/Oslo',
|
||||
]));
|
||||
$result = $this->service->events->update($calendarId, $eventId, $event);
|
||||
if ($this->canInvite && !empty($attendeeEmail)) {
|
||||
$event->setAttendees([new Google_Service_Calendar_EventAttendee(['email' => $attendeeEmail])]);
|
||||
}
|
||||
$params = ($this->canInvite && !empty($attendeeEmail)) ? ['sendUpdates' => 'all'] : [];
|
||||
$result = $this->service->events->update($calendarId, $eventId, $event, $params);
|
||||
return $result->getId();
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user