📅 支持 Discourse Calendar 插件中的 iCal Feed 同步(从 .ics URL 导入)

我已成功重建我的 Discourse 实例🥲


Discourse 的官方 discourse-calendar 插件已支持 .ics 导出,这对于在外部共享 Discourse 事件非常有用。然而,许多社区——尤其是在教育、政府或企业领域——依赖外部 iCal feeds 来发布事件信息(例如,来自 Moodle、Office365、Google Calendar 或机构 CMS 平台)。

目前,没有内置的方法可以从 .ics 源导入或同步。这限制了 Discourse 作为真正日历中心的使用,对于那些已经在其他地方发布重要日程的社区来说尤其如此。


:sparkles: 功能提案

向 Discourse Calendar 插件添加 iCal feed 同步(从 .ics URL 导入)。

:white_check_mark: 核心功能

  • 为启用日历的类别或主题配置 .ics feed URL
  • 自动将事件导入日历,与 .ics feed 匹配。
  • 指定同步间隔(例如,每小时、每天)或允许手动“立即同步”按钮。
  • 使用事件 UID 字段防止重复并干净地更新已修改的事件。

:wrench: 可选配置

  • 标记或标注导入的事件以显示其外部来源。
  • 在以下选项之间选择:
    • 单向同步(仅外部 → Discourse),
    • 双向同步(在 Discourse 内部编辑同步的事件会将更改推回——未来范围)。
  • 支持每个日历多个 .ics feed,合并到一个视图中。
  • 可视化指示事件是否已外部同步(例如,“从:outlook.university.edu 同步”)。

:teacher: 用例

行业 示例用例
教育 自动填充学生论坛的学期日期、课程表、考试等。
政府 将官方事件从 CMS 或内网同步到面向公众的社区日历
公司 镜像内部会议日历(来自 Outlook 或 Google Calendar)
活动论坛 集成来自外部提供商的演讲者列表或会议安排

:locked_with_key: 安全与隐私

  • 日历 feed 可以支持公共令牌化访问(例如,包含秘密令牌的 URL)。
  • 支持OAuth2 / Basic Auth 可以是未来的增强功能。

:paperclip: 相关


:counterclockwise_arrows_button: 兼容性

此功能不需要 discourse-events(现已弃用),并且可以与现有的 Discourse Calendar 语法([calendar][event])原生配合使用。用户仍然可以手动创建原生的 Discourse 事件——iCal 同步只是增强这些日历。


很想知道此功能是否已在路线图上——或者社区中的其他人是否会觉得它很有价值。

谢谢!

5 个赞

@Ethsim2 这将是一个巨大的功能,而且我现在正在深入研究,因为 Discourse 正在切换到 FullCalendar。

@sam 最近直接链接到了 fullcalendar.io,结果发现 FullCalendar 现在通过其官方插件系统原生支持 .ics Feed——所以繁重的工作已经由该库完成了。


:rocket: 提议:使用 FullCalendar 的原生支持启用 .ics Feed 同步

随着 FullCalendar v6 即将集成到 Discourse 中,已经为原生支持此功能奠定了基础。

FullCalendar 的 @fullcalendar/icalendar 插件(底层使用 ical.js)允许您像这样加载公共 .ics Feed:

new Calendar(calendarEl, {
  plugins: [dayGridPlugin, iCalendarPlugin],
  events: {
    url: 'https://example.com/my-calendar.ics',
    format: 'ics'
  }
});

只需这些,即可将远程 iCal Feed 渲染到日历 UI 中——无需自定义解析,即插即用。


:hammer_and_wrench: Discourse 的建议实现步骤

  1. @fullcalendar/icalendarical.js 添加到插件中(一旦 FullCalendar v6 完全落地)。
  2. 添加一个管理员/插件设置(或每个类别的选项)来输入一个或多个 .ics URL。
  3. 在客户端,将 Feed 渲染到日历视图中。
  4. (可选)实现服务器端同步,该同步:
    • 定期获取 Feed
    • 解析新/更新的事件
    • 创建或更新关联的 Discourse 主题

:counterclockwise_arrows_button: 同步频率

需要注意的是,FullCalendar 的默认 .ics 处理仅在浏览器首次加载日历时获取 Feed。这意味着:

  • 没有每日或自动刷新。
  • 用户将看到过时的副本,除非他们重新加载或手动触发刷新。
  • 没有持久性——如果用户导航离开,Feed 数据将丢失。

为了使其真正有用,Discourse 最好:

  • 运行一个每日(或计划的)Sidekiq 作业,在服务器端获取 Feed。
  • 缓存解析后的事件,以实现跨用户的一致渲染。
  • 可选地将事件链接到主题或创建新主题以实现完全集成。

这将允许正确的同步行为,并恢复之前由 Angus 的插件 处理的关键功能——但使用一个干净且可维护的基础。


:white_check_mark: 优点

  • 无缝集成来自 Google Calendar、Outlook、iCal 等的 .ics Feed。
  • 使 Discourse 成为日历消费者,而不仅仅是导出者。
  • 非常适合社区论坛、学生团体、公民活动等。
  • 完全基于受支持的 FullCalendar 功能构建——几乎不需要自定义 JavaScript。

现在日历插件又受到关注了,我很想看到这个功能实现。我很乐意帮助测试它或为概念验证做出贡献。

抱歉 @Halden42,但你的帖子让我有些困惑。

我明白 Discourse 通过升级 FullCalendar 来“修复”日历系统的基础,但我担心手动填充繁忙日历需要花费多少时间。我每天都使用 Discourse GUI 处理所有事情,不得不在界面外复制内容是不可行的。

我注意到你提到了 Angus 插件中一个我非常怀念的功能,我认为它抓住了将事件同步到 Discourse 的要点:

这部分对我来说至关重要。

但我很担心,因为你没有详细说明如何实现这一点。你能解释一下实际操作会是什么样子吗?Discourse 会为每个事件创建一个主题吗?如果源日历发生变化,它会支持更新或删除吗?

这正是我最需要依赖的部分,我还不确定我们离实现它还有多远。

再次感谢你的详细回复。

2 个赞

感谢 @Ethsim2 — 这是一个很好的跟进,我认为你的担忧是完全正确的:这不仅仅是显示来自 .ics feed 的事件,而是以一种有用、可追踪的方式将它们嵌入到 Discourse 中。

当我提到“将事件链接到主题或创建新主题”时,我设想的是一种类似于 Angus 的插件过去的工作方式的设置——feed 中的每个事件都对应 Discourse 中的一个主题,并且 feed 中的更新会随着时间的推移反映在主题中。


目前,FullCalendar 本身不持久化事件——它只在页面加载时从 feed 中渲染它们。因此,如果一个事件从 feed 中消失(即它已被取消或在外部删除),它就会在日历 UI 中悄悄消失。

但这对于大多数基于论坛的工作流程来说还不够好,特别是当事件帖子用于讨论、回复或公告时。


我建议这样做:

与其在事件从 feed 中消失时删除主题,不如让 Discourse:

  • 保留主题
  • 在顶部添加一行,例如:
    ⚠️ 此事件已被取消或从源日历中删除。
  • 根据管理员的偏好,可选地锁定或取消列出该主题

这将保留上下文,允许回复,并使取消可见——而无需删除任何内容。从技术上讲,这是非常可行的:我们只需标记 .ics 文件中不再存在的 UID,并相应地更新匹配主题的状态。


所以是的——虽然 FullCalendar 本身不管理该状态,但Discourse 可以在同步层处理它。获取 feed 的作业(例如通过 Sidekiq)将跟踪哪些事件曾经存在而现在不再存在,并相应地标记相应的主题。

如果足够多的人对此感兴趣,我认为我们可以构建一个合适的技术规范。原型制作不会很难。

1 个赞

感谢您的深思熟虑的回复 @Halden42 — 这让我明白了许多。

您在此处描述的……

……正是我在放弃 Angus 插件后一直试图恢复的核心用例。对我来说,最关键的部分不仅仅是可视化地渲染事件,而是将外部实时日历同步到论坛,其中每个事件都有一个主题,并且该事件的更改(例如取消、重新安排)会随着时间的推移反映在该主题中。

一开始,我乐于接受单向同步模型——从 .ics 到 Discourse 的只读同步——即使只是基本的更新检测也能满足我 90% 的用例。如果事件被从提要中删除,在事件主题中显示“已取消”状态将是理想的,而不是直接删除主题。

如果有一个首选的地方来提出此功能的规范——也许在 FullCalendar 升级稳定后——我将非常乐意贡献或测试。

再次感谢。

1 个赞

我们维护着多个 Office 365 日历——每个日历都有自己的 .ics feed——用于不同类型的会议:执行委员会、公众参与会议、内部工作组等。这些 feeds 已经结构良好,并由职员和管理团队定期维护。

我们迫切需要一种方法来:

  • 按类别订阅不同的 .ics feeds(例如,每个会议类型一个 feed)
  • 在相应的 Discourse 类别中自动创建一个新主题
  • 验证主题是否最终出现在正确的类别中,类似于 Angus 的插件允许我们按标签或其他元数据进行过滤的方式
  • 如果日历事件更新,则在主题中反映更改(时间、标题)
  • 如果事件被取消或从 feed 中删除,则可以选择标记或关闭该主题

对于像我们这样的委员会,类别用于管理精细的可见性——有些会议是私密的(例如,执行会议或规划会议),有些是公开的。错误归档的主题可能导致敏感数据泄露,因此类别级别的验证是必须具备的。

我们希望在即将到来的 FullCalendar 大修中看到官方支持类似的功能。这将大大减少手动工作量,并使 Discourse 作为会议协调和透明度的单一事实来源更加可行。

我是美国的一名药学专业学生,我们大学通过日历门户提供所有的轮岗时间表、考试和实践安排。信息源的 URL 不以 .ics 结尾,但在 Chrome 中打开时,它们会立即下载一个有效的 .ics 文件。所以它们绝对是标准的 iCal 信息源——只是 URL 结构不同。

直到最近,我还在使用 Angus 的插件,它完美地处理了这些信息源。每个事件都会生成一个主题,我可以将不同的信息源路由到不同的类别(例如,“治疗学”、“轮岗”、“考试”),这有助于我们学习小组保持条理。

但自从最近的 this.router 错误破坏了该插件后,我不得不禁用它——就像 Ethsim2 一样——现在没有简单的方法可以保持我们的日历同步。

如果官方插件能够支持:

  • 入站 .ics 信息源(即使 URL 不以 .ics 结尾)
  • 带有类别定向的主题创建
  • 特定于信息源的配置(例如,一个信息源 → 一个类别)
  • 更新检测和可选的事件取消处理

……这将使 Discourse 成为一个强大的学术协作工具。在插件损坏之前,它对我们来说运行得非常完美——所以我很希望看到这个功能原生实现。

如果需要测试,我很乐意私下分享一个示例日历 URL。

这同样适用于 Office 365,我明白美国许多大学都使用该生态系统。

是的,我使用那个生态系统 :+1:

2 个赞

由于最初这是一个用户及其傀儡账户,因此该主题未列出。但这些账户已被合并,现在该主题令人困惑,因为该用户似乎在与自己来回发帖。