Formuláře
Formuláře do patra dodává vestavěný plugin, ne jádro. Prakticky to znamená dvě věci: vlastník webu si ho musí v administraci zapnout (a odklikat, co plugin smí), a blok „Formulář“ se v paletě objeví teprve potom.
Co udělá vlastník webu
Sekce “Co udělá vlastník webu”- Zapne plugin „Formuláře“ v administraci v sekci Pluginy. Teprve tím se v levém panelu objeví položka Formuláře.
- Naklikne si formulář v sekci Formuláře — název, pole (text, víc řádků, e-mail, adresa, číslo, výběr), u každého popisek a jestli je povinné, a větu, kterou návštěvník uvidí po odeslání. Pořadí polí se mění přetažením nebo šipkami u řádku a celý formulář se ukládá jedním tlačítkem.
- Vloží blok „Formulář“ do stránky a v jeho nastavení si vybere ze svých formulářů. Nabídka je seznam jmen, ne pole na id — id nikdo nikam neopisuje.
- Odeslání čte ve schránce toho formuláře — tlačítko Schránka u řádku v sekci Formuláře, nebo v hlavičce editoru. Odeslání mají stavy nové / přečtené / archivované, dají se hledat podle toho, co v nich stojí, odbavovat po víc naráz a stáhnout jako tabulku.
Kdo co smí
Sekce “Kdo co smí”| Úkon | Vlastník | Redaktor |
|---|---|---|
| Naklikat a upravit formulář | ano | ano |
| Číst schránku a měnit stavy | ano | ano |
| Smazat formulář (i s poštou, která u něj je) | ano | ne |
| Smazat jednotlivá odeslání | ano | ne |
| Stáhnout schránku jako tabulku | ano | ne |
Poslední tři řádky jsou vyhrazené vlastníkovi z různých důvodů. Mazání je nevratné: zpráva od návštěvníka nemá koncept ani revizi, takže po smazání není odkud ji vzít. Proto taky smazání formuláře odnese i poštu, která u něj je — potvrzovací dialog řekne kolik zpráv, ještě než potvrdíte, a stáhnout si je předtím jde jedním tlačítkem ve schránce. Kdyby zůstaly, nebyly by k dosažení (schránka vypisuje jen existující formuláře) ani ke smazání, což je u osobních údajů návštěvníků ta nejhorší varianta. Stažení je cesta, kudy z webu odejdou osobní údaje návštěvníků v jednom souboru — není to hranice důvěrnosti (kdo schránku vidí, může si ji opsat ručně), ale hromadná kopie má být vědomé rozhodnutí vlastníka.
Každé stažení se zapíše do provozního záznamu patra — kdo, kdy, ze kterého formuláře, kolik řádků a s jakým zúžením. Ten záznam ale čte provozovatel patra, ne vy: v administraci k němu cesta nevede a drží se jen tak dlouho, jak drží provozní logy. Když potřebujete vědět, co z vašeho webu odešlo, napište nám.
Co ve stažené tabulce najdete
Sekce “Co ve stažené tabulce najdete”Sloupce jsou přijato, stav a pole formuláře v jeho současné podobě. Oddělovač je středník, protože to je to, co čeká tabulkový procesor v českém (a německém, francouzském, …) nastavení; Google Tabulky i LibreOffice si ho poznají samy.
Dvě věci, které stojí za zmínku dopředu:
- Hodnota začínající
=,+,-nebo@dostane na začátek apostrof. Takový obsah by tabulkový procesor vyhodnotil jako vzorec — a napsal ho tam návštěvník. Prakticky to znamená, že telefon zapsaný+420 777 888 999vyjde jako'+420 777 888 999; je to vědomá daň za to, že tabulka nespustí, co jí někdo cizí poslal. - Pole, které jste z formuláře mezitím smazali, sloupec nedostane. Jeho hodnota se nikam neztratila — je vidět v detailu odeslání, označená jako pole, které formulář už nemá. Do tabulky nejde proto, aby její tvar nezávisel na tom, co obsahovalo jedno odeslání ze sta.
Formulář i pošta jsou obrazovky administrace, ne pluginu
Sekce “Formulář i pošta jsou obrazovky administrace, ne pluginu”Do Sprintu 048 kreslil obojí kód pluginu ve svém pískovišti a projevovalo se to: pole nešlo přetáhnout myší, označit deset zpráv naráz taky ne. Dnes jsou to běžné obrazovky administrace a plugin si nechal jedinou práci — denní úklid podle nastavené doby uchování.
Platí za tím pravidlo, které se týká i dalších pluginů: vestavěný plugin smí mít prvotřídní obrazovku administrace, plugin nahraný ze skladu dostane jednoduchou obrazovku poskládanou z hotových prvků. Vestavěný plugin je kód, který jde do nasazení s patrem a prošel týmiž kontrolami jako zbytek; balíček od někoho cizího ne, a pouštět mu vlastní JavaScript do administrace, kde je přihlášené sezení, by byla úplně jiná úvaha o bezpečnosti.
Plugin tedy zůstává jednotkou zapnutí, souhlasu, nastavení a schopností — ne nádobou na uživatelské rozhraní. Když plugin vypnete, položka Formuláře z panelu zmizí; naklikané formuláře se ale nikam neztratí a po zapnutí jsou zpátky.
Adresa pro oznámení musí patřit členovi webu
Sekce “Adresa pro oznámení musí patřit členovi webu”Do formuláře se dá napsat adresa, na kterou přijde upozornění, že někdo odeslal. Musí to být adresa člena tohohle webu — patro na cizí adresu z formuláře neodesílá. Není to omezení pískoviště: kdyby padlo, byl by z formuláře odrazový můstek, kterým si kdokoli nechá na libovolnou adresu posílat, co mu lidé do formuláře napíšou.
Nedoručitelnou adresu poznáte z administrace, ne z toho, že se nikdo neozval: ve schránce je u konkrétního odeslání vidět, že oznámení nedošlo, a proč. Formulář se kvůli tomu, že adresa nepatří členovi webu, neodmítne uložit — odeslání návštěvníka je uložené tak jako tak, jen se o něm nikomu nenapsalo. Adresa, která nemá tvar e-mailu, se ale odmítne hned při ukládání formuláře.
Doba uchování
Sekce “Doba uchování”V nastavení pluginu (Pluginy → Formuláře) je „Jak dlouho uchovávat odeslání (dny)“ — je to jediné, co po Sprintu 048 na kartě pluginu zbylo. Nula znamená uchovávat navždy; cokoli většího jednou denně smaže odeslání starší, než je ta lhůta. Je to nastavení pluginu, ne jednotlivého formuláře — je to pravidlo o tom, jak dlouho web drží osobní data návštěvníků, a mít ho u každého formuláře zvlášť by znamenalo, že se na jeden z nich zapomene.
Co musí přidat šablona
Sekce “Co musí přidat šablona”Formulář se odesílá, takže potřebuje adresu, kam. Tenant token přitom nesmí do prohlížeče, takže se posílá na vaši doménu a teprve váš worker přidá token a přepošle to patru — týž mechanismus jako u komentářů.
1. Prostředník
Sekce “1. Prostředník”import { env } from "cloudflare:workers"import { createFormProxy } from "@patro/render"import type { APIRoute } from "astro"
export const POST: APIRoute = async ({ request }) => createFormProxy({ baseUrl: env.PUBLIC_API_BASE, token: env.PATRO_TENANT_TOKEN, onError: (error) => { console.error("patro: odeslání formuláře — ", error) }, })(request)Prostředník odpovídá vždycky přesměrováním (303) zpátky na stránku
s výsledkem v adrese. Nepřeposílá odpověď patra: chyby patra nesou české věty
a váš web může být anglický, takže ven jde jedno strojové slovo a větu k němu
složí blok z vašeho katalogu.
2. Pohled na formuláře v routě
Sekce “2. Pohled na formuláře v routě”Blok potřebuje tři věci, které ví jen stránka: adresu prostředníka, adresu návratu a výsledek posledního odeslání z adresy. Skládá se to do jednoho objektu a předá dopočtu:
import { parseFormNotice, type FormsView } from "@patro/render"import { uiText } from "./ui-text"
export const formsView = (url: URL, locale: string): FormsView => ({ endpoint: "/api/formular", text: uiText(locale).form, notice: parseFormNotice(url.searchParams), returnTo: `${url.pathname}${url.search}`, turnstileSitekey: "", // veřejný klíč Turnstile, nebo prázdno})---import { resolveListingBlock } from "@patro/render"import { formsView } from "../lib/forms"
const content = await resolveListingBlock(client, puckBody.content ?? [], { locale, forms: formsView(Astro.url, locale),})---Bez klíče forms se formulářový blok nevykreslí vůbec. Je to schválně:
formulář bez adresy prostředníka je seznam polí s tlačítkem, které nikam
nevede.
Týž klíč patří i do kontextu oblastí widgetů, jinak by formulář v patičce zůstal prázdný:
const context = { locale, locals: Astro.locals, forms: formsView(Astro.url, locale),}const paticka = await widgetAreas.content("paticka", context)3. Katalog vět
Sekce “3. Katalog vět”Popisky polí i větu po odeslání píše vlastník webu v administraci. Co je text platformy — hlášky o tom, jak odeslání dopadlo —, dodává šablona:
| klíč | k čemu je |
|---|---|
required |
značka u povinného pole (čte ji čtečka obrazovky) |
submit |
popisek tlačítka, když si autor žádný nenapsal |
noticeInvalid |
vyplněné pole je špatně |
noticeRejected |
odeslání odmítnuto (typicky neprošlo ověření, že nejste robot) |
noticeRateLimited |
z tohohle připojení přišlo za krátkou dobu moc odeslání |
noticeNotFound |
formulář mezitím zmizel |
noticeError |
nepovedlo se to a není to chyba návštěvníka |
Typ je FormText z @patro/blocks; nic si nemusíte vymýšlet, chybějící klíč
nahlásí typecheck.
4. Skript pro podmíněná pole
Sekce “4. Skript pro podmíněná pole”Vlastník webu si u pole může nastavit, že se má ukázat jen při určité hodnotě
jiného pole nad ním („Číslo objednávky“ jen když si návštěvník vybral
„reklamace“). Schovávání za běhu obstarává malá komponenta z @patro/render —
vložte ji do hlavičky dokumentu tam, kde už vkládáte skript Turnstile:
---import FormConditions from "@patro/render/FormConditions.astro"---<head> {maFormular && <FormConditions />}</head>Podmínku ať radši dá jen tam, kde je formulář: Astro váže skripty na komponenty, takže nevykreslená komponenta do stránky nic nepřidá.
Bez ní podmíněná pole fungovat nebudou — a projeví se to tím, že se návštěvníkovi nikdy neukážou. Nerozbije to formulář: server se schovaným polem počítá stejně jako prohlížeč, takže ho nevyžaduje a jeho hodnotu neuloží.
Odeslání funguje i bez JavaScriptu
Sekce “Odeslání funguje i bez JavaScriptu”Blok formuláře je statický a odeslání je obyčejný <form method="post">.
Prohlížeč ho odešle, prostředník vrátí 303 zpátky na stránku s výsledkem
v adrese a blok z něj složí větu. Po přijatém odeslání se místo formuláře ukáže
věta, kterou si napsal vlastník webu. Nic z toho nepotřebuje JavaScript.
Praktický důsledek: formulář smí stát i uvnitř „Sekce“ nebo „Sloupců“, na rozdíl od bloku diskuse, který se oživuje a musí být na první úrovni.
Jediná výjimka jsou podmíněná pole
Sekce “Jediná výjimka jsou podmíněná pole”Ta si skript vyžádají — jinak by se pole neměla podle čeho schovávat. Je to padesát řádků, které Astro vloží rovnou do stránky (1 395 B po zabalení, změřeno), ne runtime frameworku; ostrůvek by formuláři zakázal stát ve slotu, což je zrovna to, co odstavec výš slibuje.
Bez JavaScriptu se podmíněné pole neukáže, a je to vědomá volba: opačná
varianta (ukázat všechno) by znamenala, že required na poli, které podle
autora nemá platit, zablokuje odeslání přímo v prohlížeči. Takhle se formulář
odeslat dá.
Turnstile
Sekce “Turnstile”Když má web nastavený veřejný klíč Turnstile (turnstileSitekey v pohledu
výš), blok vykreslí widget a shell stránky vloží skript Turnstile. Widget se
kreslí implicitně — skript si prvek najde sám a token vloží do formuláře
jako skryté pole, takže se ani tady nepotřebuje žádný náš JavaScript.
Klíč patří vám a tajný protějšek patru. Když tedy Turnstile zapínáte, zapněte obojí naráz: klíč bez tajného protějšku znamená widget, jehož token nikdo neověří, a tajný protějšek bez klíče znamená odmítnuté každé odeslání.
Ochrana proti spamu
Sekce “Ochrana proti spamu”Tři vrstvy a každá řeší něco jiného:
- Past na roboty — pole, které člověk nevidí a robot vyplní. Vyhodnocuje ji patro, ne váš prostředník (ten ji jen přepošle), a odpověď je k nerozeznání od přijatého odeslání: robot se nesmí dozvědět, že narazil.
- Strop na jedno připojení — z jednoho otisku IP projde pět odeslání za deset minut. Je to brzda proti zaplnění úložiště, ne hlavní ochrana.
- Turnstile, když si ho web nastaví.
Otevřená IP návštěvníka se nikde neukládá — patro z ní počítá otisk se solí vašeho webu.