Hostia a odkazy pre hostí
Žiadateľ bez účtu je TicketGuest a jeho polia sa ukladajú cez attributes-for-laravel:
$ticket = Tickets::make()->subject('Broken link')->guest(['name' => 'Jo', 'email' => '[email protected] '])->create();
$guest = Tickets::guests()->resolve(['name' => 'Jo', 'email' => '[email protected]']);
$known = Tickets::guests()->find(['email' => '[email protected]']); // read-only: the guest, or null
Tickets::guests()->update($guest, ['phone' => '+421 900 000 000']);
$link = Tickets::guests()->linkFor('TCK-9'); // a model or a reference; = Tickets::for($ticket)->guestLink()
$moved = Tickets::guests()->convert($guest, $user); // when the guest registers
Tickets::for($ticket)->by($agent)->revokeGuestAccess(); // void every link issued so farPolia hosťa
O tom, čo sa hostí pýtate, rozhodujete vy. tickets.guests.fields musí byť neprázdna mapa s práve jedným poľom display a každé pole má názov zodpovedajúci ^[a-z][a-z0-9_]{0,63}$. Dodaná sada:
// config/tickets.php
'guests' => [
'fields' => [
'name' => ['type' => 'string', 'rules' => ['required', 'string', 'max:120'], 'display' => true],
'email' => ['type' => 'string', 'rules' => ['nullable', 'email:rfc', 'max:191'], 'identifying' => true, 'route' => 'mail', 'normalize' => 'email'],
'phone' => ['type' => 'string', 'rules' => ['nullable', 'string', 'max:32'], 'identifying' => true, 'route' => 'vonage', 'normalize' => 'phone', 'encrypted' => false],
],
// …
],| Atribút | Význam |
|---|---|
type | Hodnota AttributeType z attributes-for-laravel (string, integer, …); predvolene string. |
rules | Validačné pravidlá Laravelu pre hodnotu. |
display | Práve jedno pole je zobrazované meno hosťa. |
identifying | Nájde vracajúceho sa hosťa (skúša sa v poradí konfigurácie); unikátne medzi hosťami; nikdy nesmie byť šifrované. |
route | Kanál notifikácií, na ktorý toto pole smeruje (mail, vonage, …) — číta ho routeNotificationFor(). |
normalize | email (orezanie, malé písmená) alebo phone (odstránenie medzier) pred porovnaním. |
encrypted | Uložiť hodnotu šifrovane (nie pre identifikačné polia). |
Rozpoznanie hosťa
resolve() a každý tiket založený s poliami hosťa:
- Hodnoty sa zvalidujú podľa pravidiel poľa a normalizujú (email: orezaný, malými písmenami; phone: bez medzier). Chyby majú kľúč fields.<name> z Tickets::guests() a guest.<name> pri zakladaní tiketu či zmene žiadateľa — e-mail hosťa a vlastné pole email sa teda nikdy nezrazia. Hosť sa vyhodnotí skôr, než sa validujú vlastné polia.
- Identifikačné polia sa skúšajú v poradí konfigurácie; prvá zhoda je hosť. Prázdne polia nájdeného hosťa sa doplnia; odlišné neidentifikačné hodnoty zostanú, pokiaľ nie je zapnuté tickets.guests.update_on_resolve.
- Ak sa údaje zhodujú s hosťom, no nesú inú hodnotu ďalšieho identifikačného poľa, ktoré hosť má, vznikne nový hosť len s tými identifikačnými hodnotami, ktoré nemá žiadny iný hosť — tiket sa tak nikdy nedostane ku kontaktu inej osoby.
- Soft-deleted hosť, ktorý sa znova ozve, sa obnoví; bez zhody sa hosť vytvorí. Dva súbežné prvé tikety od toho istého nového hosťa skončia pri jednom hosťovi.
find($fields) hľadá presne ako rozpoznanie, no nikdy nič nevytvorí, nedoplní ani nezvaliduje: neznáme názvy ignoruje, soft-deleted hosťa nevráti a bez identifikačnej hodnoty odpovie null. Je to čítanie, preto ho fake nezaznamená.
Konverzia
convert($guest, $user) v jednej transakcii presmeruje žiadateľa každého tiketu a každý riadok sledovania z hosťa na používateľa (kde už používateľ tiket sleduje, sledovanie hosťa sa zahodí), zapíše aktivitu requester_changed, uvoľní identifikačné hodnoty hosťa, hosťa soft-deletne a spustí GuestConverted. Komentáre, ktoré hosť napísal, majú ako autora naďalej hosťa.
Odkazy pre hostí
Žiadateľ-hosť — alebo hosť medzi sledujúcimi, kým je zapnuté tickets.watchers.can_view — otvorí tiket cez dočasný podpísaný odkaz:
$url = Tickets::for($ticket)->guestLink(); // the guest requester
$url = Tickets::for($ticket)->guestLink($ccGuest); // a guest watcher; anyone else is refused
Tickets::for($ticket)->revokeGuestAccess(); // voids every link issued so farPredvolený Guests\SignedRouteLinkGenerator podpíše tickets.guest.show s číslom tiketu, kľúčom hosťa a v = guest_access_version tiketu, s platnosťou tickets.guests.link_ttl (P30D). Potrebuje routy pre hostí (tickets.routes.enabled aj tickets.guests.enabled); keď sú vypnuté, vyhodí InvalidTicketsConfigurationException s návodom na opravu. Notifikácie pre hostí zakaždým vložia novo vygenerovaný odkaz.
Podpis pokrýva jednu routu, takže odkaz z e-mailu otvorí len GET /tickets/guest/{ticket}. Jeho odpoveď obsahuje podpísané URL akcií, každú podpísanú pre ten istý tiket, hosťa, v a platnosť:
{
"data": { "reference": "TCK-7", "subject": "…", "status": {…}, "fields": [], "attachments": [] },
"messages": [ { "id": 12, "body": "…", "role": "agent", … } ],
"links": {
"self": "https://…/api/tickets/guest/TCK-7?guest=…&v=1&expires=…&signature=…",
"reply": "https://…/api/tickets/guest/TCK-7/replies?…",
"transitions": { "close": "https://…/transitions/close?…" },
"attachments": { "<uuid>": "https://…/attachments/<uuid>?…" }
}
}links.reply je null, keď je tiket uzavretý; links.transitions uvádza len práve povolené requester_transitions. Odpovede sa odosielajú ako hosť, s rovnakými automatizáciami.
Jedna odpoveď pre každý zlý odkaz: EnsureGuestTicketAccess overí podpis sám, potom či je hosť žiadateľom-hosťom alebo hosťom medzi sledujúcimi a či je v aktuálne. Expirované, upravené, zneplatnené odkazy, odkazy iného tiketu, iného hosťa aj zmazaného tiketu dostanú rovnakú odpoveď 403 {message, code: guest_link_invalid} — nie je čo skúmať. revokeGuestAccess(), zlúčenie alebo uzavretie pri tickets.guests.revoke_on_close zvýšia v a zneplatnia každý odkaz aj každú vloženú URL akcie.
Samostatný frontend
Keď hostia používajú vašu SPA namiesto surového API, naviažte generátor, ktorý podpísanú URL API zabalí do odkazu na frontend. Frontend volá vložené URL presne tak, ako sú — nikdy ich neskladá nanovo —, takže podpis zostane platný:
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Tickets\Contracts\GuestLinkGenerator;
use RoundlyConsulting\Tickets\Guests\SignedRouteLinkGenerator;
use RoundlyConsulting\Tickets\Models\Ticket;
final readonly class FrontendGuestLinks implements GuestLinkGenerator
{
public function __construct(private SignedRouteLinkGenerator $signed) {}
public function for(Ticket $ticket, Model $recipient): string
{
return 'https://help.example.com/guest?link='.rawurlencode($this->signed->for($ticket, $recipient));
}
}// config/tickets.php
'guests' => ['link_generator' => App\Tickets\FrontendGuestLinks::class, /* … */],Frontend prečíta link, zavolá naň GET, vykreslí data a messages a posiela POST na links.reply ({body, attachments[]?}) alebo na URL z links.transitions.* ({reason?, payload?}). Tento generátor stále potrebuje routy pre hostí, pretože ich balí. Frontend, ktorý sa endpointov balíka pre hostí nikdy nedotkne, môže vracať akúkoľvek URL, ktorú si vyhodnotí sám — potom routy pre hostí vypnite.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.