跳转到内容

连接 Google Calendar

本指南介绍如何将 Google Calendar 连接到工作区。连接是按工作区进行的:它会将该工作区的事件以只读方式同步到 Control Center。完整说明请参阅日历与日程。

  1. 在侧边栏中打开日历。
  2. 在日历侧边栏中点击添加日历账户。(同一设置区块也位于设置 → 工作区 → 个人资料与身份中的 Google 日历下方。)
  3. 选择授权方式:
    • 使用 Control Center 的 Google 应用 — 无需任何设置。当你的构建自带该应用时,这就是默认选项。
    • 使用我自己的 Google Cloud 客户端 — 粘贴来自你自己项目的客户端 ID 和密钥(参见自带 Google 客户端)。
  4. 点击连接 Google 日历。对话框会显示一个短代码和一个指向 Google 设备页面的链接。
  5. 在任意设备上打开该页面,输入代码并批准所请求的访问权限。对话框会自行关闭,你的事件随即开始同步。

执行这次交换、并保存所得刷新令牌的是服务器,而不是你的设备——这也是为什么代码是在“任意设备”上批准,而不是必须在本应用中批准。

账户只会连接到当前活动的工作区。切换工作区后,你看到的将是该工作区的日历。

连接流程会请求 calendar.readonly 以及你的邮箱——内置应用和你粘贴的客户端请求的作用域相同。Control Center 只读取事件;它不会在 Google 上创建、编辑、删除事件,也不会回复邀请。

日程由服务器掌控:它每两分钟扫描一次每个工作区已连接的账户,并把事件写入该工作区的数据库。客户端从不直接与 Google 通信——它们读取服务器写入的内容。

扫描是增量的。每个日历的首次扫描会拉取一个滚动窗口(过去 60 天、未来 90 天)并记录 Google 的同步令牌;此后的扫描会出示该令牌,只收到发生变化的内容,这也是两分钟的节奏得以可行的原因。该窗口每 24 小时重新完整同步一次,每当 Google 使令牌失效时也会如此。

刷新令牌存放在服务器端的 secrets.json 中,位于服务器的数据目录下,仅所有者可读写(0600)——不在操作系统钥匙串中,也绝不会出现在客户端设备上。

一个工作区可以连接多个 Google 账户(例如工作和个人账户)。为每个账户重复连接步骤即可;它们的事件会合并到同一个月/周/议程视图中。每个账户独立同步和刷新,也可以单独断开连接。

如果 Google 永久性地使某个账户的令牌失效(会话被撤销或长期过期),同步就会停止,Control Center 会在日历上显示重新连接横幅,并发送一条桌面通知。点击重新连接并批准新的代码;横幅会在下一次同步成功后消失。

在日历侧边栏(或设置 → 工作区 → 个人资料与身份)中,点击该账户上的断开连接。这会删除其已同步的事件,并清除服务器上存储的令牌。

没有连接图形界面的服务器,可以在自己的终端上连接同一个账户:

终端窗口
GOOGLE_OAUTH_CLIENT_ID=<id> GOOGLE_OAUTH_CLIENT_SECRET=<secret> \
cc_server calendar connect --data-dir <dir> --workspace <workspace-id>

它会打印一个代码和一个 URL,等待批准,然后存储令牌并在下一次扫描时同步。

从源码构建的版本完全不附带 Google 客户端,因此必须提供客户端 ID 和密钥——设置 GOOGLE_OAUTH_CLIENT_ID 和 GOOGLE_OAUTH_CLIENT_SECRET。没有 --google-client-id 标志(未知标志会被忽略)。如果没有这一对环境变量,该命令会以缺少客户端的错误退出。

自带 Google 客户端(分支版本与自托管)

标题为“自带 Google 客户端(分支版本与自托管)”的部分

发行版自带一个 Google 客户端,因此大多数人无需接触这部分内容。如果你是自行从源码构建、运行自己的服务器,或者希望同意屏幕上显示你自己的项目,才需要自带客户端。

  1. 在 Google Cloud Console 中启用 Google Calendar API 并配置 OAuth 同意屏幕,添加 calendar.readonly、openid 和 email 作用域。在应用尚未通过验证时,把你本人添加为测试用户。在同意屏幕上添加 calendar.events 并不会启用 RSVP——Control Center 从不请求该作用域。
  2. 创建一个应用类型为 TVs and limited input devices 的 OAuth 客户端 ID,并复制客户端 ID 和客户端密钥。
  3. 既可以按每次连接提供(在对话框中选择使用我自己的 Google Cloud 客户端),也可以通过 GOOGLE_OAUTH_CLIENT_ID 和 GOOGLE_OAUTH_CLIENT_SECRET 在服务器范围内提供。

服务器范围内的一对凭据会在所有地方取代内置的那一对,包括“使用 Control Center 的 Google 应用”选项背后——因此在你自己的服务器上,该选项用的就是你的应用。

客户端密钥永远不会离开服务器:没有任何 RPC 响应会携带它,通过服务器自己的客户端连接的账户存储的只是一个标记,而不是这对凭据的副本,因此轮换密钥只需用新值重启即可。

现象 可能原因
对话框没有提供内置选项 该构建不附带 Google 客户端(源码构建),或者服务器启动时只提供了这对凭据中的一半。客户端 ID 和密钥两者都必需
启动流程时出现 invalid_scope 该 Cloud 项目未允许将 Calendar 用于设备码客户端。请改用环回客户端或 Web 客户端项目
Google 返回 invalid_client 该客户端不是 TVs and limited input devices 客户端,或者客户端 ID 和密钥来自不同的客户端
批准成功,但同步内容为空 你的账户不是同意屏幕上的测试用户,或者未授予 calendar.readonly
代码在你批准之前就已过期 设备码的有效期很短。重新开始连接以获取一个新的代码
RSVP 时显示“无法更新你的回复” 这是预期行为:连接流程从不请求 calendar.events
同步停止,服务器日志中出现刷新警告 连接该账户时使用的客户端已不再配置。重新连接该账户,或恢复该客户端的 ID 和密钥