Pozvánky
Tím vydáva pozvánky s expiráciou, voliteľne určené pre konkrétny e-mail. Každá nesie rolu a náhodný kód; po prijatí sa člen pridá s touto rolou:
use RoundlyConsulting\Teams\Facades\Teams;
// Default expiry from config, targeted at one email address.
$invite = Teams::for($team)->invites()->create(role: 'admin', email: '[email protected]');
// Every option:
$invite = Teams::for($team)->invites()->create(
role: 'member',
expiresAt: now()->addDays(14), // null → invites.expires_after
email: '[email protected]', // null → an open invite
invitedBy: $currentUser, // stored as a morph
meta: ['note' => 'design team'],
maxUses: 1, // default 1; null = unlimited
);
$invite->code; // random, invites.code_length characters
$invite->expires_at; // Carbon
// The model shortcut takes the same parameters in the same order (role first):
$invite = $team->invite('member', now()->addDays(3), email: '[email protected]');Pozvánky vypršia po invites.expires_after (7 dní), ak nezadáte expiresAt, a kódy majú invites.code_length (32) znakov. Skratka $team->invite() spustí to isté volanie managera.
Prijatie
use RoundlyConsulting\Teams\Facades\Teams;
// 1. By code — the invite is looked up for you
$member = Teams::invites()->accept($code, $user, email: $user->email);
// 2. With a resolved invite
$member = Teams::invites()->accept($invite, $user, email: $user->email);
// 3. On the invite model — the same manager call
$member = $invite->acceptBy($user, $user->email);
Teams::invites()->find($code); // ?InvitePrijatie znova načíta pozvánku so zámkom a prebehne týmito kontrolami v tomto poradí, každá s typovanou výnimkou:
- Vypršaná → InviteExpiredException.
- Vyčerpaná — uses dosiahlo max_uses alebo jednorazová pozvánka už bola spotrebovaná → InviteExhaustedException.
- Zrušená → InviteNotFoundException.
- Pozvánka na konkrétny e-mail s iným alebo chýbajúcim e-mailom → InviteEmailMismatchException. E-maily sa porovnávajú bez ohľadu na veľkosť písmen a ukladajú sa malými písmenami, takže [email protected] sa zhoduje s [email protected].
- Tím pozvánky bol zmazaný → InviteNotFoundException.
- Teams::invites()->accept() s neznámym kódom vyhodí InviteNotFoundException ešte pred kontrolami.
$invite->isExpired(); // expires_at has passed
$invite->isExhausted(); // uses reached max_uses (never true when unlimited)Po úspechu sa člen pridá s rolou pozvánky a prepojí sa s ňou, uses sa zvýši a spustí sa InviteAccepted. Jednorazová pozvánka sa pri prvom prijatí zmaže; viacnásobná zostáva, kým sa nevyčerpá.
Prijatie je atomické: miesto sa obsadí podmieneným updatom v tej istej transakcii ako pridanie člena, takže jednorazovú pozvánku využije práve jeden človek a odkaz s N miestami nikdy nepustí N + 1 ľudí, nech o ne súperí koľkokoľvek kariet či používateľov. Kto už je aktívnym členom, dostane svoje členstvo nezmenené — nespotrebuje miesto a jeho rola sa nikdy neprepíše, takže vlastník, ktorý otvorí odkaz s rolou member, zostane vlastníkom. Expirované alebo odobraté členstvo sa cez pozvánku obnoví s rolou pozvánky.
Opätovné odoslanie a zrušenie
Teams::for($team)->invites()->resend($invite); // Invite — rotates the code, extends the expiry from now
Teams::for($team)->invites()->revoke($invite); // bool — soft-delete
Teams::for($team)->invites()->pending(); // Collection<Invite> — the team's unexpired invites
// Model shorthand, same code path:
$invite = $invite->resend();
$invite->revoke();Opätovné odoslanie vymení kód a predĺži platnosť od teraz, pričom rola, e-mail aj meta zostanú, a spustí InviteResent. Zrušenie pozvánku mäkko zmaže a spustí InviteRevoked. Ak handlu podáte pozvánku iného tímu, vyhodí InviteNotFoundException. Znova ju poslať môžete aj z CLI:
php artisan teams:invites:resend {code} # prints the new codeDopyty na pozvánky
use RoundlyConsulting\Teams\Models\Invite;
Invite::query()->pending()->get(); // not yet expired
Invite::query()->forEmail('[email protected]')->get();
$team->invites()->pending()->get();
$invite->team; // the Team
$invite->invitedBy; // the inviting model (MorphTo), or nullRouta a controller na prijatie
Balík neregistruje žiadne routy, URL máte pod kontrolou vy. Invite::getRouteKeyName() vracia code, takže parameter routy {invite} sa naviaže na kód pozvánky. Publikujte stuby a dostanete hotovú dvojicu rout aj controller:
php artisan vendor:publish --tag="teams-stubs"// routes/teams.php — require it from routes/web.php
use App\Http\Controllers\AcceptInviteController;
use Illuminate\Support\Facades\Route;
Route::middleware(['web', 'auth', 'verified'])->group(function (): void {
Route::get('teams/invites/{invite}', [AcceptInviteController::class, 'show'])
->name('teams.invites.show');
Route::post('teams/invites/{invite}', [AcceptInviteController::class, 'store'])
->name('teams.invites.accept');
});namespace App\Http\Controllers;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Blade;
use RoundlyConsulting\Teams\Facades\Teams;
use RoundlyConsulting\Teams\Models\Invite;
class AcceptInviteController extends Controller
{
// GET — shows a confirmation form, never accepts. Swap the template for your own view.
public function show(Invite $invite): Response
{
return response(Blade::render(<<<'BLADE'
<form method="POST" action="{{ route('teams.invites.accept', $invite) }}">
@csrf
<p>Join {{ $invite->team?->name }} as {{ $invite->role }}?</p>
<button type="submit">Accept invite</button>
</form>
BLADE, ['invite' => $invite]));
}
// POST — CSRF-protected by the web group; only a verified email is offered.
public function store(Request $request, Invite $invite): RedirectResponse
{
$user = $request->user();
$email = $user instanceof MustVerifyEmail && $user->hasVerifiedEmail()
? $user->getEmailForVerification()
: null;
$member = Teams::invites()->accept($invite, $user, email: $email);
return redirect()->route('teams.show', $member->team_id);
}
}- GET nikdy nemení stav: GET teams/invites/{code} len zobrazí potvrdzovací formulár a prijatie je POST chránený CSRF — náhľad odkazu ani <img> na cudzej stránke tak prihláseného používateľa do tímu nepridá.
- Obe routy sú za middleware ['web', 'auth', 'verified'].
- Controller ponúkne pozvánke na konkrétny e-mail adresu účtu, až keď je overená (MustVerifyEmail); inak takúto pozvánku odmietne.
Oba súbory sú vaše a môžete ich upravovať — inline šablónu nahraďte vlastným view. Controller presmeruje na routu teams.show, ktorú si definuje vaša aplikácia.
Upratovanie
teams:invites:prune — alebo Teams::invites()->prune() — natrvalo zmaže pozvánky, ktoré vypršali pred viac ako mesiacom. Invite je aj Prunable s rovnakým oknom a php artisan model:prune zasiahne navyše aj zrušené a spotrebované (mäkko zmazané) pozvánky:
php artisan teams:invites:prune # force-delete invites that expired over a month ago (= Teams::invites()->prune())
php artisan model:prune # Invite is Prunable too — includes revoked and consumed onesPrejavte 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.