From 725d7316c4cc5fcda22448f11ddf6e8bf1ceec1e Mon Sep 17 00:00:00 2001 From: Nikita Karamov Date: Sat, 2 Sep 2023 19:02:17 +0200 Subject: [PATCH] Replace /api/share with / + errors --- CHANGELOG.md | 3 +- src/components/instance-select.astro | 17 ++++++- src/pages/api/detect/[domain].ts | 4 +- src/pages/api/share.ts | 31 ------------- src/pages/index.astro | 67 +++++++++++++++++++++++++--- src/styles/main.scss | 17 ++++++- 6 files changed, 97 insertions(+), 42 deletions(-) delete mode 100644 src/pages/api/share.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fa9a9f..f206df3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,8 @@ now takes seconds! This comes with changes, though: Some changes came with the name change: -- **changed API endpoint path**: ~~`/api/toot`~~ → `/api/share` +- **changed API endpoint path**: ~~`/api/toot`~~ → `/` + - just send a POST request instead of a GET request with the same body ### Added diff --git a/src/components/instance-select.astro b/src/components/instance-select.astro index 264763e..e0c505b 100644 --- a/src/components/instance-select.astro +++ b/src/components/instance-select.astro @@ -6,7 +6,7 @@ * SPDX-FileCopyrightText: © 2023 Nikita Karamov * SPDX-License-Identifier: AGPL-3.0-only */ -const { prefilledInstance } = Astro.props; +const { instance, errors } = Astro.props; --- @@ -20,10 +20,23 @@ const { prefilledInstance } = Astro.props; id="instance" list="popular-instances" required + aria-invalid={Boolean(errors)} + aria-errormessage={errors ? "instance-error" : undefined} aria-describedby="https-label" - value={prefilledInstance} + value={instance} /> + { + errors && ( +

+ {errors} +

+ ) + }
{ const softwareName = await getSoftwareName(domain); if (softwareName === undefined) { - return error("Could not detect software; NodeInfo not present."); + return error("Could not detect Fediverse project."); } if (!(softwareName in supportedProjects)) { - return error(`"${softwareName}" is not supported yet.`); + return error(`Fediverse project "${softwareName}" is not supported yet.`); } const publishConfig = supportedProjects[softwareName] as ProjectPublishConfig; diff --git a/src/pages/api/share.ts b/src/pages/api/share.ts deleted file mode 100644 index c94a8a7..0000000 --- a/src/pages/api/share.ts +++ /dev/null @@ -1,31 +0,0 @@ -/*! - * This file is part of Share₂Fedi - * https://github.com/kytta/share2fedi - * - * SPDX-FileCopyrightText: © 2023 Nikita Karamov - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { getUrlDomain } from "@lib/url"; -import type { APIRoute } from "astro"; -import type { Detection } from "./detect/[domain]"; -import { error } from "@lib/response"; - -export const post: APIRoute = async ({ redirect, request, url }) => { - const formData = await request.formData(); - - const text = (formData.get("text") as string) || ""; - const instanceHost = - getUrlDomain(formData.get("instance") as string) || "mastodon.social"; - - const response = await fetch(new URL(`/api/detect/${instanceHost}`, url)); - const json = await response.json(); - if (json.error) { - return error(json.error); - } - - const { domain, endpoint, params } = json as Detection; - const publishUrl = new URL(endpoint, `https://${domain}/`); - publishUrl.search = new URLSearchParams([[params.text, text]]).toString(); - return redirect(publishUrl.toString(), 303); -}; diff --git a/src/pages/index.astro b/src/pages/index.astro index 779a7f4..200fea3 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -9,15 +9,56 @@ import Layout from "@layouts/layout.astro"; import InstanceSelect from "@components/instance-select.astro"; +import { getUrlDomain } from "@lib/url"; +import type { Detection } from "./api/detect/[domain]"; + const searchParameters = new URL(Astro.request.url).searchParams; -const prefilledText = searchParameters.get("text"); -const prefilledInstance = searchParameters.get("instance"); +let text: string | null = searchParameters.get("text"); +let instance: string | null = searchParameters.get("instance"); + +const errors = { text: "", instance: "" }; +if (Astro.request.method === "POST") { + const formData = await Astro.request.formData(); + text = formData.get("text") as string | null; + instance = formData.get("instance") as string | null; + + if (typeof text !== "string" || text.length === 0) { + errors.text += "Please enter post text. "; + } + + let detection: Detection | undefined; + if (typeof instance !== "string" || instance.length === 0) { + errors.instance += "Please enter instance domain. "; + } else { + instance = getUrlDomain(instance); + + const detectResponse = await fetch( + new URL(`/api/detect/${instance}`, Astro.url), + ); + const detectJson = await detectResponse.json(); + if (detectJson.error) { + errors.instance += detectJson.error + " "; + } else { + detection = detectJson; + } + } + + const hasErrors = Object.values(errors).some(Boolean); + if (!hasErrors && detection !== undefined) { + const { domain, endpoint, params } = detection; + const publishUrl = new URL(endpoint, `https://${domain}/`); + publishUrl.search = new URLSearchParams([ + [params.text, text as string], + ]).toString(); + // eslint-disable-next-line unicorn/prefer-module + return Astro.redirect(publishUrl.toString(), 303); + } +} ---
- +