私密日历事件的已验证 ICS 源

公共 ICS 导出功能最近通过

GET /discourse-post-event/events.ics 重新引入,这是在

重新添加完整的 ICS 导出

中工作后的一项重大改进。

目前,此端点似乎仅限于匿名用户可见的事件。因此,私有类别或对默认 everyone 组有限制类别的事件无法在外部日历客户端(例如 Google Calendar、Outlook)中订阅。

是否可以支持对该端点的经过身份验证的访问,类似于 Discourse 处理私有 RSS/Atom 提要的方式(例如,通过每个用户的令牌或只读 API 密钥)?

这不会更改任何权限规则——它只会允许日历客户端访问用户已授权查看的事件。

根据之前建议的公共 ICS 提要的重新引入,我将此作为一个单独的、范围明确的请求提出。

1 个赞

在仔细研究了代码之后,我编写了一个非常简单的代理,它处理了创建用户 API 密钥并将其传递给 API 所需的各种障碍;它还生成了一个用户需要在其日历应用中粘贴的链接:

希望所有这些最终都能进入 Discourse 代码,届时就不再需要它了——在此期间,我分享此信息,希望能让其他人的生活更轻松。

我本周早些时候在此拉取请求中添加了该功能。但是,为非技术用户生成用户 API 密钥的可用性(ergonomics)并不理想。为了实现无缝集成,我正在跟进:

这试图使其尽可能友好

1 个赞

我刚刚合并了这个功能,你能试一下吗 @Ethsim2

1 个赞

感谢——我可以确认认证后的信息源本身现在在我这边正在正确生成。

剩下的问题似乎是客户端兼容性:Google 日历和 Outlook 都似乎不愿意直接订阅这种形式的经过身份验证的 ICS 信息源,所以目前我计划通过在单容器 Discourse 安装前面放置一个主机级别的 Nginx 反向代理来解决这个问题,并改为在那里提供一个纯粹的 .ics 文件。

由于我使用的是标准的单容器设置,我认为这意味着需要将端口 80/443 从容器上移开,让 Discourse 监听一个内部的高位端口,然后让主机 Nginx 代理论坛,并同时提供一个静态的日历信息源路径。

粗略地说,我预期会使用的命令是:

# 1. 安装主机 nginx + certbot
sudo apt update
sudo apt install -y nginx snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot

# 2. 停止 Discourse 容器以便释放 80/443 端口
cd /var/discourse
sudo ./launcher stop app

# 3. 编辑容器配置,使 Discourse 不再直接绑定到 80/443
sudo nano /var/discourse/containers/app.yml

然后在 app.yml 中将 expose 部分从:

expose:
  - "80:80"
  - "443:443"

更改为类似以下内容:

expose:
  - "127.0.0.1:8080:80"

并且,如果存在,则移除容器 SSL / Let’s Encrypt 模板,以便 TLS 在主机反向代理处终止。

然后重建:

cd /var/discourse
sudo ./launcher rebuild app

然后在主机级别创建一个 Nginx 站点,例如:

sudo nano /etc/nginx/sites-available/discourse

内容大致如下:

server {
    listen 80;
    listen [::]:80;
    server_name forum.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /private-calendar/ethan.ics {
        alias /var/www/private-calendar/ethan.ics;
        default_type text/calendar;
        add_header Content-Type "text/calendar; charset=utf-8";
    }
}

启用它并重新加载:

sudo mkdir -p /var/www/private-calendar
sudo mkdir -p /var/www/certbot
sudo ln -s /etc/nginx/sites-available/discourse /etc/nginx/sites-enabled/discourse
sudo nginx -t
sudo systemctl reload nginx

然后使用 Certbot 获取 Let’s Encrypt 证书,并让它更新 Nginx 配置:

sudo certbot --nginx -d forum.example.com
sudo nginx -t
sudo systemctl reload nginx

之后,Nginx 配置通常也会包含一个 HTTPS 服务器块,例如:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name forum.example.com;

    ssl_certificate /etc/letsencrypt/live/forum.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/forum.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /private-calendar/ethan.ics {
        alias /var/www/private-calendar/ethan.ics;
        default_type text/calendar;
        add_header Content-Type "text/calendar; charset=utf-8";
    }
}

到那时,我就可以在主机上使用脚本/定时器来获取经过身份验证的 Discourse ICS 并写入:

/var/www/private-calendar/ethan.ics

这样 Google 日历/Outlook 就可以像订阅正常的公共 ICS URL 一样订阅它了。

因此,从我的角度来看,Discourse 这边现在看起来已经解决了;实际剩下的难点主要在于主要的日历客户端对经过身份验证的 ICS 信息源处理得不太好,这就是我目前回退到使用公共代理/静态文件方法的原因。

我还在假设 Certbot 是这里最简单的途径,因为它可以直接针对主机 Nginx 管理 Let’s Encrypt 的签发/续订。我也可以使用 acme.sh,但我的印象是对于这种特定设置,它会是一种更手动化的选择,而不是最直接的路径。

等等,什么?

我用Google日历用得好好的,我的同事们也是。

它与Google日历不兼容的哪一部分!?

啊——谢谢,这有助于缩小范围。

就我这边而言,Google 日历确实接受订阅 URL(通过“从 URL 添加”),但我看到的行为是:

  • 日历添加成功
  • 但是,它完全不显示任何事件

所以这不是 URL 被拒绝的情况——更像是从 Google 的角度来看,该信息源显示为空。

考虑到原始 ICS 明确包含 VEVENT 条目(例如带有 UIDDTSTARTSUMMARY 等),这让我想可能是以下情况之一:

  • Google 过滤掉了过去的事件(我的大部分测试数据都是历史数据)
  • 或者与信息源的解释方式有关(例如时间范围、缓存或标头)

如果有什么需要我检查的信息源本身的内容,请告诉我。

2 个赞

您能检查一下 /logs 有没有错误吗?我刚刚修复了一个错误,该错误是旧的重复事件导致了信息流失败。

如果是同一个错误,您需要更新。

我得回溯到晚上 7 点之前,因为有很多与 Discourse AI 相关的警告/错误——token 限制。

1 个赞
1 个赞