diff --git a/site/e2e/text.spec.ts b/site/e2e/text.spec.ts
index 8df5c61..90d1671 100644
--- a/site/e2e/text.spec.ts
+++ b/site/e2e/text.spec.ts
@@ -1,7 +1,7 @@
import { DOWNLOADS, expect, test, VERSION, type Page } from "./fixtures.ts";
import { TEXT, word, type Key, type Lang } from "../src/text.ts";
-const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice";
+const REPO = "https://github.com/ELY-Open-Source/ElyOffice";
const APPS = ["ElyDoc", "ElyTable", "ElyShow", "ElyPDF", "ElyTree", "ElyMark"];
const RELEASES = `${REPO}/releases/latest`;
@@ -114,10 +114,10 @@ test.describe("English locale", () => {
});
test("a failed version read shows as an error", async ({ page }) => {
- await page.route("**/release.json", (r) => r.fulfill({ status: 502, body: "Gitea answered 500" }));
+ await page.route("**/release.json", (r) => r.fulfill({ status: 502, body: "GitHub answered 500" }));
await page.goto("/");
await expect.poll(() => errors.length).toBe(1);
- expect(errors[0]).toContain("Gitea answered 500");
+ expect(errors[0]).toContain("GitHub answered 500");
await expect(page.locator("#download h2")).toHaveText("Ely Office");
for (const c of await page.locator("[data-t=count]").all()) await expect(c).toBeHidden();
errors = [];
@@ -174,20 +174,3 @@ test("the hero links share one baseline in either language", async ({ browser })
await page.close();
}
});
-
-test("the download area tells how to open an unnotarized app", async ({ browser }) => {
- for (const [locale, words] of [
- ["en-US", ["System Settings", "Privacy & Security", "Open Anyway"]],
- ["zh-CN", ["系统设置", "隐私与安全性", "仍要打开"]],
- ] as const) {
- const page = await browser.newPage({ locale, reducedMotion: "reduce" });
- await page.goto("/");
- const steps = page.locator("#download [data-t=unsigned]");
- await expect(steps).toBeVisible();
- for (const word of words) await expect(steps).toContainText(word);
- await page.locator(".lang").click();
- await expect(steps).toBeVisible();
- await expect(steps).not.toContainText(words[0]);
- await page.close();
- }
-});
diff --git a/site/src/icons.ts b/site/src/icons.ts
index 7af811f..25efa4b 100644
--- a/site/src/icons.ts
+++ b/site/src/icons.ts
@@ -3,7 +3,7 @@ import { said, type Key } from "./text.ts";
const ICONS = {
download: ``,
- gitea: ``,
+ github: ``,
};
/** A link with `icon` before its keyed text. */
diff --git a/site/src/main.ts b/site/src/main.ts
index 1fd28fa..6898bd4 100644
--- a/site/src/main.ts
+++ b/site/src/main.ts
@@ -11,7 +11,7 @@ import { said, speak, word, type Lang } from "./text.ts";
import { RELEASES, latest } from "./release.ts";
import { iconLink } from "./icons.ts";
-const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice";
+const REPO = "https://github.com/ELY-Open-Source/ElyOffice";
const app = document.querySelector("#app");
if (!app) throw new Error("index.html has no #app");
@@ -19,7 +19,7 @@ if (!app) throw new Error("index.html has no #app");
const hero = document.createElement("header");
const title = document.createElement("h1");
title.textContent = "Ely Office";
-const source = iconLink("gitea", "source", REPO);
+const source = iconLink("github", "source", REPO);
const download = iconLink("download", "get", RELEASES);
const links = document.createElement("div");
links.className = "links";
@@ -40,7 +40,7 @@ const count = said("p", "count");
count.hidden = true;
const get = said("a", "get");
get.href = RELEASES;
-footer.append(version, count, said("p", "platforms"), said("p", "needs"), said("p", "unsigned"), get);
+footer.append(version, count, said("p", "platforms"), said("p", "needs"), get);
const toggle = said("button", "other");
toggle.className = "lang";
diff --git a/site/src/release.ts b/site/src/release.ts
index 23dbc44..7277b73 100644
--- a/site/src/release.ts
+++ b/site/src/release.ts
@@ -1,5 +1,5 @@
-// Gitea redirects this to the newest release.
-export const RELEASES = "https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice/releases/latest";
+// GitHub redirects this to the newest release.
+export const RELEASES = "https://github.com/ELY-Open-Source/ElyOffice/releases/latest";
export type Release = { version: string; downloads: number };
diff --git a/site/src/text.ts b/site/src/text.ts
index 3796a0f..4339b7c 100644
--- a/site/src/text.ts
+++ b/site/src/text.ts
@@ -15,7 +15,6 @@ const en = {
download: "Download",
platforms: "Out now for macOS, Windows and Linux.",
needs: "macOS 14 or later, Apple silicon.",
- unsigned: "Not notarized. If macOS blocks the app, open System Settings › Privacy & Security and click Open Anyway.",
get: "Download",
count: "{n} downloads so far.",
source: "Source",
@@ -53,7 +52,6 @@ const zh: typeof en = {
download: "下载",
platforms: "macOS、Windows 与 Linux 版已发布。",
needs: "macOS 14 或更新,Apple 芯片。",
- unsigned: "未经公证。macOS 拦下应用时,打开“系统设置 › 隐私与安全性”,点“仍要打开”。",
get: "前往下载",
count: "已下载 {n} 次。",
source: "源码",
diff --git a/site/worker/index.ts b/site/worker/index.ts
index 081630d..4c8fbc7 100644
--- a/site/worker/index.ts
+++ b/site/worker/index.ts
@@ -1,34 +1,38 @@
// Answers /release.json with the newest release and downloads.
-const REPO = "https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/ElyOffice";
-const PAGE = 50;
+const REPO = "https://api.github.com/repos/ELY-Open-Source/ElyOffice";
+const PAGE = 100;
type Cached = RequestInit & { cf: { cacheTtl: number; cacheEverything: boolean } };
type Asset = { name: string; download_count: number };
type Release = { tag_name: string; assets: Asset[] };
+// A token lifts GitHub's limit for the shared egress addresses: `wrangler secret put GITHUB_TOKEN`.
+type Env = { GITHUB_TOKEN?: string };
-const init: Cached = {
- headers: { accept: "application/json", "user-agent": "ely-office-site" },
- cf: { cacheTtl: 300, cacheEverything: true },
-};
-
-async function read(path: string): Promise {
+async function read(env: Env, path: string): Promise {
+ const headers: Record = {
+ accept: "application/vnd.github+json",
+ "user-agent": "ely-office-site",
+ "x-github-api-version": "2022-11-28",
+ };
+ if (env.GITHUB_TOKEN) headers.authorization = `Bearer ${env.GITHUB_TOKEN}`;
+ const init: Cached = { headers, cf: { cacheTtl: 300, cacheEverything: true } };
const res = await fetch(`${REPO}${path}`, init);
- if (!res.ok) throw new Error(`Gitea answered ${res.status} for ${path}`);
+ if (!res.ok) throw new Error(`GitHub answered ${res.status} for ${path}`);
return (await res.json()) as T;
}
/** The newest release's version, without the v. */
-async function version(): Promise {
- const { tag_name: tag } = await read("/releases/latest");
- if (!/^v\d+\.\d+\.\d+$/.test(tag)) throw new Error(`Gitea's latest tag is ${JSON.stringify(tag)}`);
+async function version(env: Env): Promise {
+ const { tag_name: tag } = await read(env, "/releases/latest");
+ if (!/^v\d+\.\d+\.\d+$/.test(tag)) throw new Error(`GitHub's latest tag is ${JSON.stringify(tag)}`);
return tag.slice(1);
}
/** Downloads of every release; update manifests are checks, not downloads. */
-async function downloads(): Promise {
+async function downloads(env: Env): Promise {
let total = 0;
for (let page = 1; ; page++) {
- const releases = await read(`/releases?limit=${PAGE}&page=${page}`);
+ const releases = await read(env, `/releases?per_page=${PAGE}&page=${page}`);
for (const { assets } of releases) {
for (const a of assets) {
if (!Number.isInteger(a.download_count)) throw new Error(`${a.name} has no download count`);
@@ -40,9 +44,9 @@ async function downloads(): Promise {
}
export default {
- async fetch(): Promise {
+ async fetch(_request: Request, env: Env): Promise {
try {
- const [v, n] = await Promise.all([version(), downloads()]);
+ const [v, n] = await Promise.all([version(env), downloads(env)]);
return Response.json({ version: v, downloads: n }, { headers: { "cache-control": "public, max-age=300" } });
} catch (e) {
return new Response(String(e), { status: 502 });