Google 日历 API - 创建活动 + Google Meet 链接

Dev*_*Joe 0 php google-calendar-api google-cloud-platform

我知道有很多关于这个问题的请求;但他们似乎都没有回答我的问题。为了自动生成 Google 日历约会,包括自动生成相应的 Google Meet 链接,我执行了以下操作:

  1. 创建谷歌云项目
  2. 为相关帐户启用 Google Calendar API
  3. 创建新的 Google 服务帐户
  4. 获取该服务帐户的电子邮件地址,并将其添加到 Google 日历的设置下,以允许对该电子邮件进行更改/管理访问权限。
  5. 下载最新版本的 google api 客户端 ( https://packagist.org/packages/google/apiclient )。
  6. 转到 Google 服务帐户 > 密钥 > 生成的新密钥文件为JSON,比方说access.json
  7. 在 PHP 中实现用于生成日历 API 约会的代码,包括最近的补丁 ( https://developers.google.com/calendar/api/releases?hl=de#september_07_2020 ):

        putenv('GOOGLE_APPLICATION_CREDENTIALS=my/key/data/directoy/access.json');
        $client = new Client();
        $client->useApplicationDefaultCredentials();
        $client->addScope(Google_Service_Calendar::CALENDAR);
        $client->setSubject("{address_explained_below}");
        
        // Set up the Calendar API service
        $service = new Google_Service_Calendar($client);
        
        // Create a new event on Google Calendar
        $event = new Google_Service_Calendar_Event(
            [
                'summary'        => 'Meeting',
                'start'          => [
                    'dateTime' => '2023-04-07T10:00:00-07:00',
                    // Replace with your desired start time
                    'timeZone' => 'America/Los_Angeles',
                    // Replace with your desired timezone
                ],
                'end'            => [
                    'dateTime' => '2023-04-07T11:00:00-07:00',
                    // Replace with your desired end time
                    'timeZone' => 'America/Los_Angeles',
                    // Replace with your desired timezone
                ]
            ]
        );
        
        // Set the event's conference data to use Google Meet
        $conferenceRequest = new Google_Service_Calendar_CreateConferenceRequest();
    
        $conferenceRequest->setRequestId(uniqid());
        
        $solution_key = new Google_Service_Calendar_ConferenceSolutionKey();
        $solution_key->setType("hangoutsMeet");
        $conferenceRequest->setConferenceSolutionKey($solution_key);
        
        $conference = new Google_Service_Calendar_ConferenceData();
        
        $conference->setCreateRequest($conferenceRequest);
        
        $event->setConferenceData($conference);
        
        // Insert the event into the user's calendar
        $calendarId = 'myCalendarsID';
        $event = $service->events->insert(
            $calendarId,
            $event,
            [ 'conferenceDataVersion' => 1 ]
        );
        
        var_dump($event);
        
        // Retrieve the generated Google Meet link from the event's conference data
        $meetLink = $event->getHangoutLink();
Run Code Online (Sandbox Code Playgroud)

我确实尝试遵循本论坛中有关此问题的所有其他帖子的建议;但没有任何效果,我现在收到一个400 Bad Request错误,无论type我设置(hangoutsMeet或其他什么),说Invalid conference type value.。我缺少什么?我遇到过这个;这可能是特定于库的,并且在不使用库的情况下实现原始 HTTP REST API 调用会更好吗?

更新:

使用Google 提供的测试功能在此处触发此请求后:

GET https://www.googleapis.com/calendar/v3/calendars/{calendarId}

我确实可以确认那hangoutsMeet是在allowedConferenceSolutionTypes.

{
 "kind": "calendar#calendar",
 "etag": "secret",
 "id": "secret",
 "summary": "secret",
 "timeZone": "secret",
 "conferenceProperties": {
  "allowedConferenceSolutionTypes": [
   "hangoutsMeet"
  ]
 }
}
Run Code Online (Sandbox Code Playgroud)

因此,我想,根据@Lorena Gomez(谢谢!)评论,我必须“向我的服务帐户授予域范围委托,并模拟具有该日历权限的用户”,尽管我不太清楚是什么这实际上意味着/确实如此。

关于域范围的委派,我现在已经为注册的服务帐户执行了此操作,如此处指定。这似乎有效,尽管我在相关服务帐户下的“IAM 和管理”屏幕中的服务帐户面板中看不到任何差异。这个授权是否需要一些时间才能生效?

我一直在进一步挖掘,显然这里有这行代码:

$client->setSubject($user_to_impersonate);

用于模拟具有该日历权限的用户。但这里的值应该是多少呢$user_to_impersonate?我已经提供了我为其范围授予域范围委托的服务帐户的电子邮件地址https://www.googleapis.com/auth/calendar,在这种情况下我仍然得到:

Google_Service_Exception: { 
  "error": { 
    "errors": [ 
      { 
        "domain": "global", 
        "reason": "invalid", 
        "message": "Invalid conference type value." 
      } 
    ], 
    "code": 400, 
    "message": "Invalid conference type value." 
  } 
}
Run Code Online (Sandbox Code Playgroud)

然后我用实际拥有日历的谷歌帐户的电子邮件地址进行了尝试,结果是:

Google_Service_Exception: { 
  "error": "unauthorized_client", 
  "error_description": "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested." 
} 

Error code: 401 
Run Code Online (Sandbox Code Playgroud)

然后,我使用被授予域范围委派的服务帐户的用户 ID 进行尝试,此时我得到:

Caught Google_Service_Exception: { 
  "error": "invalid_request", 
  "error_description": "Invalid principal" 
} 

Error code: 400 
Run Code Online (Sandbox Code Playgroud)

所以我不明白,我还缺少什么?我已将上面的代码更新为现在的状态(该字符串address_explained_below被上述三个尝试替换)。

我现在进行了最后一次尝试,创建了一个新的服务帐户,为其启用了域范围的委派,生成了访问密钥,并将其上传到服务器。然后,当使用新创建的服务帐户的电子邮件地址运行上面的代码时,出现错误404 Not found。然后,我转到相关日历的 Google 日历设置,并在下面添加了服务帐户的电子邮件地址Share with specific people or groups(我已经翻译了该部分;这是您可以授予其他人访问您的日历的部分)。这样做并重新运行上面的脚本后,我现在再次获得了400 Error Invalid conference type value.

我唯一能想到的是,putenv调用将变量的值(使用 进行检查)设置为从服务器根目录getenv到保存凭据的文件的绝对路径。.json这是意图吗?如何读取/访问凭证?只是问因为.json文件位于0500目录中并且.json文件本身也在目录中0500,但这应该没问题吗?好吧,我被困住了。

我的一个想法是:您在 Google Workspace 域中验证的域实际上必须是您发送 API 请求/运行上述代码的域吗?因为目前情况并非如此...

Dev*_*Joe 7

由于我一直在努力解决这个问题,并且在这个论坛中有无数关于此设置问题/对设置步骤的困惑的帖子;这是分步指南,解释如何为您所需的 Google 日历正确设置以编程方式生成 Google 日历活动,+ 生成相关的 Google Meet 链接

您主要需要什么:

步骤是:

  1. 为您的企业域创建一个 Google Workspace 帐号。为简单起见,请使用您尝试集成的 Google 日历的 Gmail 地址。
  2. 以防您感到困惑:系统会要求您提供您的企业域名,然后创建一个 Google Workspace 用户,该用户似乎是带有您企业域名的电子邮件地址。这并不代表有效的电子邮件地址(目前),甚至在 g-mail 中也不代表。这只是登录您的 Google Workspace 帐号的用户名。
  3. 完成验证域的过程(通常只需将TXT条目添加到域的 DNS 记录中即可)。
  4. Create new User由于持续弹出提示,该步骤Setup Gmail似乎对于设置新的 Google Workspace 帐户是强制性的,但实际上根本没有必要。您应该特别注意通过 Gmail 设置电子邮件,因为这会要求您MX从 DNS 记录中删除所有记录,并插入来自 Google 的记录。这会将步骤 2 中提到的 Google Workspace 用户名激活为 Gmail 帐户。但是,由于您必须删除MX企业域以前的 DNS 设置的所有记录才能执行此操作,这将导致您的主机注册的所有当前企业电子邮件将停止工作。这就是为什么如果您已经为您的业务域设置了电子邮件提供商,那么跳过这一部分是没有问题的。
  5. 在此阶段,一切都已通过 Google Workspace 帐号完成。
  6. 创建一个谷歌云平台帐户。为简单起见,我将再次使用您尝试集成的 Google 日历的 Gmail 地址。
  7. 在其中,转到“菜单”>“API 和服务”,然后单击“+激活 API 和服务”按钮,搜索Google Calendar API、单击它并启用它。
  8. 同样在“菜单”>“API 和服务”下,单击“凭据”
  9. 单击“+ 创建新凭据”>“服务帐户”以创建新的服务帐户。将此视为 HTTP 客户端“机器人”,它将用于验证从服务器到 Google Calendar API 的请求,以创建活动 + 会议链接。
  10. 创建后,单击它,转到Keys > Add New Key > JSON,并将获得的 JSON 存储在安全位置(例如path/to/your/access_data.json)。
  11. 接下来,您必须向您创建的服务帐户授予域范围委托,以便一切正常工作。为此,请返回到您刚刚创建的服务帐户的“详细信息”,单击“高级设置” ,您会在其中看到“域范围委派”,然后单击“打开 Google 管理工作区控制台”。这将要求您登录 Google Workspace 帐户;使用您在 1 中创建的用户名。请注意,您需要使用 Google Workspace 帐号的用户名才能登录,而不是您在创建帐号时使用的电子邮件地址。这很正常。
  12. 在 Google Workspace 帐号中,转到安全 > 访问和数据控制 > API 控制。请注意,此菜单可能不会显示,具体取决于您创建 Google Workspace 帐号的方式;因此,按照上一步所述,通过 Google Cloud Platform 打开 Google Workspace 管理控制台非常重要。如果您的 Google Workspace 帐号中此前尚未显示该菜单,这将使API 控件链接可见。在其中,请按照此处所写的说明进行操作。
  13. 接下来,转到您想要以编程方式生成事件的 Google 日历,然后转到该日历的“设置”。向下滚动,直到您看到“向个人或群组授予访问权限”之类的内容,然后在其中添加您的 Google Workspace 用户名以执行操作Make changes and manage accesses。等到它被保存。如果您不这样做,您的 API 请求将导致404 (Not found) error.
  14. 进一步向下滚动到Integrate Calendar,并记下Calendar ID,这将在下一步的代码中需要。这可能是一个电子邮件地址,是的,不要混淆。
  15. 完成后,为了最终将您的请求编码到 Google Calendar API,请下载适合您系统的Google API 客户端库。就我而言,这是 PHP,最终通过 API 创建 Google 日历事件并生成相应的 Google Meet 链接的示例脚本是:
<?php
declare(strict_types=1);

namespace MyGoogleAPIStuff;

use Google\Client;
use Google_Service_Calendar;
use Google_Service_Calendar_Event;

final class Calendar
{
    
    /**
     * Generate New Google Calendar Event + related Google Meet Link
     *
     * @return string Google Meet Link of the scheduled event
     */
    
    public static function create_calendar_meeting_and_google_meet_link(): string
    {
        
        // Set up credentials for the Calendar API
        putenv(
            assignment: 'GOOGLE_APPLICATION_CREDENTIALS=path/to/your/access_data.json'
        );
        
        // Initiate API Client
        $client = new Client();
        $client->useApplicationDefaultCredentials();
        
        // Define Scope for which authorization is needed to execute event creation in Google Calendar API
        $client->addScope(
            scope_or_scopes: Google_Service_Calendar::CALENDAR
        );
        
        // Impersonate Google Workspace User to submit request to Google Calendar API, otherwise won't work
        $client->setSubject(
            subject: "Here, you have to enter your Google Workspace Account Username"
        );
        
        // Set up the Calendar API service
        $service = new Google_Service_Calendar(
            clientOrConfig: $client
        );
        
        // Create a new event on Google Calendar
        $event = new Google_Service_Calendar_Event(
            [
                'summary'        => 'Meeting',
                'start'          => [
                    'dateTime' => '2023-04-10T10:00:00-07:00',
                    'timeZone' => 'America/Los_Angeles',
                ],
                'end'            => [
                    'dateTime' => '2023-04-10T11:00:00-07:00',
                    'timeZone' => 'America/Los_Angeles',
                ],
                // Payload section needed to create a unique Google Meet link for the appointment
                'conferenceData' => [
                    'createRequest' => [
                        'requestId'             => uniqid(),
                        'conferenceSolutionKey' => [
                            'type' => 'hangoutsMeet'
                        ]
                    ]
                ],
            ]
        );
        
        // Insert the event into the targeted Google Calendar
        $event = $service->events->insert(
            calendarId: "Here, you have to enter your Google Calendar ID",
            postBody:   $event,
            optParams:  [ 'conferenceDataVersion' => 1 ] // To allow for Google Meet Link creation
        );
        
        // Retrieve the generated Google Meet link from the event's conference data
        return $event->getHangoutLink();
        
    }
    
}
Run Code Online (Sandbox Code Playgroud)

我一直遇到的问题是,如果您不向该行提供 Google Workspace 帐号的用户名:

$client->setSubject(
subject: "Here, you have to enter your Google Workspace Account Username"
);
Run Code Online (Sandbox Code Playgroud)

例如,即使您提供 GCP 帐户或 GCP 服务帐户的电子邮件地址,您也会400 (Bad Request)从 API 收到错误消息,显示Invalid conference type value。这可能会令人困惑,因为可能是这样的情况(对我来说就是这种情况),通过this检查您的日历允许的关注类型,仍然会告诉您:

...
"allowedConferenceSolutionTypes": [
   "hangoutsMeet"
  ]
...
Run Code Online (Sandbox Code Playgroud)

这意味着相关日历允许创建 Google Meet 链接。因此,您从 API 得到的错误Invalid conference type value是不准确的;实际问题是,您没有模拟 Google Workspace 帐号用户,您曾使用该用户对用于发送请求的服务帐号实施全网域委派。真的很挣扎这个。

无论如何,完成上述所有操作后,一切都应该可以正常工作。再说一次,这个实现不会免费执行。许多网站告诉您,Google Calendar API 的使用是免费的,甚至是 chatGPT 等。但要执行我的分步指南中解释的操作,您需要有效的 Google Workspace 订阅;我已经通过与 Google 的快速支持会议验证了这一点。只是让你知道。

快乐的安排!