'datetime', 'accepted_at' => 'datetime', ]; protected static function booted(): void { static::creating(function (ProjectInvitation $invitation) { $invitation->token ??= Str::random(32); $invitation->expires_at ??= now()->addDays(7); }); } public function project(): BelongsTo { return $this->belongsTo(Project::class); } public function inviter(): BelongsTo { return $this->belongsTo(User::class, 'invited_by'); } public function isExpired(): bool { return $this->expires_at->isPast(); } public function isPending(): bool { return !$this->accepted_at && !$this->isExpired(); } public function accept(User $user): void { if ($this->isExpired()) { throw new \RuntimeException('Invitation has expired'); } if ($this->accepted_at) { throw new \RuntimeException('Invitation has already been accepted'); } $this->project->users()->attach($user->id, ['role' => $this->role]); $this->update(['accepted_at' => now()]); } }