Repository: louislam/uptime-kuma
File: server/model/status_page.js (JavaScript)

Code before:
     */
    static async renderRSS(statusPage, slug) {
        const { heartbeats } = await StatusPage.getRSSPageData(statusPage);

        let proto = config.isSSL ? "https" : "http";
        let host = `${proto}://${config.hostname || "localhost"}:${config.port}/status/${slug}`;

        const feed = new Feed({
            title: "uptime kuma rss feed",
            description: "feed for monitors that are down",
            link: host,
            language: "en", // optional, used only in RSS 2.0, possible values: http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
            updated: new Date(), // optional, default = today
        });

        heartbeats.forEach(heartbeat => {
            feed.addItem({
                title: `${heartbeat.name} is down`,
                description: `${heartbeat.name} has been down since ${heartbeat.time}`,
                id: heartbeat.monitorID,
                date: new Date(heartbeat.time),
            });
        });

        return feed.rss2();
    }

    /**
     * SSR for status pages
     * @param {string} indexHTML HTML page to render
     * @param {StatusPage} statusPage Status page populate HTML with
     * @returns {Promise<string>} the rendered html
     */
    static async renderHTML(indexHTML, statusPage) {
        const $ = cheerio.load(indexHTML);

        const description155 = marked(statusPage.description ?? "")
            .replace(/<[^>]+>/gm, "")
            .trim()
            .substring(0, 155);

        $("title").text(statusPage.title);
        $("meta[name=description]").attr("content", description155);

        if (statusPage.icon) {
            $("link[rel=icon]")
                .attr("href", statusPage.icon)
                .removeAttr("type");

            $("link[rel=apple-touch-icon]").remove();
        }

Review comment (bug):
Not quite true.
That is just the last heartbeat that failed.
That description however can be misinterpreted as the first `DOWN` heartbeat (=> the total downtime for said heatbeat).

Also: I don't think that it has to be down, right? (we also have `MAINTENANCE`, `UP` and `Pending` as statuses, but I would need to look up if they can be heartbeats)

Code after:
    }

    /**
     * SSR for RSS feed
     * @param {statusPage} statusPage object
     * @param {slug} slug from router
     * @returns {Promise<string>} the rendered html
     */
    static async renderRSS(statusPage, slug) {
        const { heartbeats, statusDescription } = await StatusPage.getRSSPageData(statusPage);

        let proto = config.isSSL ? "https" : "http";
        let host = `${proto}://${config.hostname || "localhost"}:${config.port}/status/${slug}`;

        const feed = new Feed({
            title: "uptime kuma rss feed",
            description: `current status: ${statusDescription}`,
            link: host,
            language: "en", // optional, used only in RSS 2.0, possible values: http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
            updated: new Date(), // optional, default = today
        });

        heartbeats.forEach(heartbeat => {
            feed.addItem({
                title: `${heartbeat.name} is down`,
                description: `${heartbeat.name} has been down since ${heartbeat.time}`,
                id: heartbeat.monitorID,
                date: new Date(heartbeat.time),
            });
        });

        return feed.rss2();
    }

    /**
     * SSR for status pages
     * @param {string} indexHTML HTML page to render
     * @param {StatusPage} statusPage Status page populate HTML with
     * @returns {Promise<string>} the rendered html
     */
    static async renderHTML(indexHTML, statusPage) {
        const $ = cheerio.load(indexHTML);

        const description155 = marked(statusPage.description ?? "")
            .replace(/<[^>]+>/gm, "")
            .trim()
            .substring(0, 155);

        $("title").text(statusPage.title);
        $("meta[name=description]").attr("content", description155);