team members and invitations
This commit is contained in:
@@ -55,6 +55,11 @@ class Project extends Model
|
||||
return $this->hasMany(AlertRule::class);
|
||||
}
|
||||
|
||||
public function invitations(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProjectInvitation::class);
|
||||
}
|
||||
|
||||
public function regenerateKeys(): void
|
||||
{
|
||||
$this->update([
|
||||
@@ -62,4 +67,23 @@ class Project extends Model
|
||||
'dsn_secret_key' => Str::uuid()->toString(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function userRole(User $user): ?string
|
||||
{
|
||||
return $this->users()
|
||||
->where('users.id', $user->id)
|
||||
->first()
|
||||
?->pivot
|
||||
?->role;
|
||||
}
|
||||
|
||||
public function hasOwner(User $user): bool
|
||||
{
|
||||
return $this->userRole($user) === 'owner';
|
||||
}
|
||||
|
||||
public function hasAdmin(User $user): bool
|
||||
{
|
||||
return in_array($this->userRole($user), ['owner', 'admin']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ProjectInvitation extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'project_id',
|
||||
'invited_by',
|
||||
'email',
|
||||
'role',
|
||||
'token',
|
||||
'expires_at',
|
||||
'accepted_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'expires_at' => '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()]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user